luogu P3521 [POI2011]ROT-Tree Rotations
阿新 • • 發佈:2020-12-31
題面傳送門
考慮兩顆子樹如果交換,那麼其實對其它子樹與這兩顆子樹的貢獻是沒有影響的。
那麼線上段樹合併時判斷一下是否要交換即可。
程式碼實現:
#include<cstdio> #define beg(x) int cur=s.h[x] #define end cur #define go cur=tmp.z #define l(now) f[now].l #define r(now) f[now].r #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; int n,m,k,x,y,z,root[400039],cnt,cntt,l[400039],r[400039],tot; long long ans; struct fhq{int l,r,f;}f[19000039]; inline void get(int x,int l,int r,int &now){ if(!now)now=++cntt;f[now].f++; if(l==r)return; int m=l+r>>1; if(x<=m) get(x,l,m,l(now)); else get(x,m+1,r,r(now)); } inline long long find(int x,int y,int w,int l,int r){ if(!x||!y){ if(!x) return 0; else return f[x].f*w; } if(l==r)return f[x].f*w; long long ans=0;int m=l+r>>1; ans+=find(r(x),r(y),w,m+1,r)+find(l(x),l(y),w+f[r(y)].f,l,m); return ans; } inline int merge(int x,int y,int l,int r){ if(!x||!y) return x+y;f[x].f+=f[y].f; if(l==r)return x; int m=l+r>>1; l(x)=merge(l(x),l(y),l,m);r(x)=merge(r(x),r(y),m+1,r); return x; } inline int dfs(int last){ int now=++cnt; scanf("%d",&x); if(!x){ l[now]=dfs(now);r[now]=dfs(now); long long un=find(root[l[now]],root[r[now]],0,1,n),wn=find(root[r[now]],root[l[now]],0,1,n); ans+=min(wn,un); root[now]=merge(root[l[now]],root[r[now]],1,n); } else get(x,1,n,root[now]); return now; } int main(){ // freopen("1.in","r",stdin); register int i; scanf("%d",&n); dfs(0); printf("%lld\n",ans); }