cjb-poi2011treerotations
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#define rep(i,n) for(int i=1;i<=n;i++)
#define mp make_pair
#define pb push_back
using namespace std;
#define PI 3.1415926535897932384626433
#define N 1000010
#define LF double
#define stack stck
struct node
{
int l,r,cnt,key;
}a[1000100];
int root[3000100];
int n,tot=1;
long long cnt,ans=0;
void update(int x){ a[x].cnt=a[a[x].l].cnt+a[a[x].r].cnt+1; }
int merge(int x,int y)
{
if (x==0||y==0)return x+y;
if (a[x].key>a[y].key)
{
a[x].r=merge(a[x].r,y);
update(x);
return x;
}
else
{
a[y].l=merge(x,a[y].l);
update(y);
return y;
}
}
void split(int t,int k,int &x,int &y)
{
if (t==0){x=0; y=0; return;}
if (t<=k)
{
x=t;
split(a[t].r,k,a[t].r,y);
}
else
{
y=t;
split(a[t].l,k,x,a[t].l);
}
if (x!=0)update(x);
if (y!=0)update(y);
}
void insert(int x,int rt)
{
int r1,r2;
split(root[rt],x,r1,r2);
a[x].l=a[x].r=0;
a[x].cnt=1;
cnt=cnt+a[r2].cnt;
root[rt]=merge(merge(r1,x),r2);
}
void dfs(int x,int rt)
{
int l=a[x].l;
int r=a[x].r;
if (l)dfs(l,rt);
insert(x,rt);
if (r)dfs(r,rt);
}
void solve(int t)
{
int x; scanf("%d",&x);
if (x!=0)
{
root[t]=x;
a[x].l=a[x].r=0;
a[x].cnt=1;
return;
}
int l=++tot;
solve(l);
int r=++tot;
solve(r);
if (a[root[l]].cnt<a[root[r]].cnt)swap(l,r);
long long sum=1ll*a[root[l]].cnt*a[root[r]].cnt;
cnt=0;
dfs(root[r],l);
ans+=min(cnt,sum-cnt);
root[t]=root[l];
}
int main()
{
srand(time(0));
cin>>n;
rep(i,n)a[i].key=random();
solve(1);
cout<<ans<<endl;
return 0;
}
}}}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#define rep(i,n) for(int i=1;i<=n;i++)
#define mp make_pair
#define pb push_back
using namespace std;
#define PI 3.1415926535897932384626433
#define N 1000010
#define LF double
#define stack stck
struct node
{
int l,r,cnt,key;
}a[1000100];
int root[3000100];
int n,tot=1;
long long cnt,ans=0;
void update(int x){ a[x].cnt=a[a[x].l].cnt+a[a[x].r].cnt+1; }
int merge(int x,int y)
{
if (x==0||y==0)return x+y;
if (a[x].key>a[y].key)
{
a[x].r=merge(a[x].r,y);
update(x);
return x;
}
else
{
a[y].l=merge(x,a[y].l);
update(y);
return y;
}
}
void split(int t,int k,int &x,int &y)
{
if (t==0){x=0; y=0; return;}
if (t<=k)
{
x=t;
split(a[t].r,k,a[t].r,y);
}
else
{
y=t;
split(a[t].l,k,x,a[t].l);
}
if (x!=0)update(x);
if (y!=0)update(y);
}
void insert(int x,int rt)
{
int r1,r2;
split(root[rt],x,r1,r2);
a[x].l=a[x].r=0;
a[x].cnt=1;
cnt=cnt+a[r2].cnt;
root[rt]=merge(merge(r1,x),r2);
}
void dfs(int x,int rt)
{
int l=a[x].l;
int r=a[x].r;
if (l)dfs(l,rt);
insert(x,rt);
if (r)dfs(r,rt);
}
void solve(int t)
{
int x; scanf("%d",&x);
if (x!=0)
{
root[t]=x;
a[x].l=a[x].r=0;
a[x].cnt=1;
return;
}
int l=++tot;
solve(l);
int r=++tot;
solve(r);
if (a[root[l]].cnt<a[root[r]].cnt)swap(l,r);
long long sum=1ll*a[root[l]].cnt*a[root[r]].cnt;
cnt=0;
dfs(root[r],l);
ans+=min(cnt,sum-cnt);
root[t]=root[l];
}
int main()
{
srand(time(0));
cin>>n;
rep(i,n)a[i].key=random();
solve(1);
cout<<ans<<endl;
return 0;
}