wc上第一次听这个题就感觉很有想法,于是想了个倍增,只能过50分,后来周而进讲了分块存图的方法,可惜只能用动态树维护,经ATM启发,每次分块后都不裂块,以适应倍增的树形态不变的性质,也就是后来钟沛林讲的方法,实现起来还比较容易,只是细节难以处理。
每个块我只存块状树深度,左右端点,每要处理一个点,二分其所处的块,倍增存2^k步的块,2^k步的点,2^k到块顶的距离,然后各种特判维护实际距离。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> struct block { int d,l,r; }st[500000]; int ss,num,f[500000][30],g[500000][30],c[500000][30],a2[30],dis1,dis2,ans; void init() { int i,k; st[ss=1].d=0,st[1].l=1,st[1].r=1,num=1; for (i=1,k=29,a2[0]=1;i<=k;a2[i]=a2[i-1]*2,i++) ; } int search(int x) { int l=1,r=ss,mid; for (;l<=r;) { mid=(l+r)>>1; if (st[mid].r<x) l=mid+1;else r=mid-1; } return l; } void path(int a,int b) { int aa,bb,k,i; aa=search(a),st[++ss].d=st[aa].d+1,st[ss].l=num+1,st[ss].r=num+b,num+=b; f[ss][0]=aa;g[ss][0]=a,c[ss][0]=a-st[aa].l+1; k=(int)log2(st[ss].d); for (i=1;i<=k;i++) if (a2[i]<=st[ss].d) g[ss][i]=g[f[ss][i-1]][i-1], c[ss][i]=c[ss][i-1]+c[f[ss][i-1]][i-1], f[ss][i]=f[f[ss][i-1]][i-1]; } int make(int a,int d) { int e,ia,k,aa; e=d,aa=search(a),ia=a; if (a-d>=st[aa].l) return (a-d); e-=a-st[aa].l,ia=st[aa].l; for (k=0;e>0;) { if ((e-c[aa][k]>=0)&&(c[aa][k]!=0)) e-=c[aa][k],ia=g[aa][k],aa=f[aa][k],k++; else { if (0==k) e-=c[aa][k],ia=g[aa][k],aa=f[aa][k],k++; else k--; } } e+=ia-st[aa].l;return ia-e; } int min(int a,int b) {return (a<b) ? a : b;} int dig(int a,int b) { int ya,yb,e,aa,bb,ia,ib,pd,k,oa,ob; aa=search(a),bb=search(b),pd=0,oa=a,ob=b; if (aa==bb) {k=(a+b)/2;if ((a>b)&&((a+b)%2==1)) k++;return k;} if (st[aa].d<st[bb].d) e=aa,aa=bb,bb=e,e=a,a=b,b=e,pd=1; ya=aa,yb=bb; e=st[aa].d-st[bb].d,dis1=0,dis2=0,ia=st[aa].l,ib=st[bb].l,k=0; for (;e;k++,e>>=1) if ((e&1)==1) dis1+=c[aa][k],ia=g[aa][k],aa=f[aa][k]; for (k=0;aa!=bb;) { if (f[aa][k]!=f[bb][k]) dis1+=c[aa][k],ia=g[aa][k],aa=f[aa][k],dis2+=c[bb][k],ib=g[bb][k],bb=f[bb][k],k++; else { if (0==k) dis1+=c[aa][k],ia=g[aa][k],aa=f[aa][k],dis2+=c[bb][k],ib=g[bb][k],bb=f[bb][k],k++; else k--; } } int flag=dis2; if (flag!=0) if (ia<ib) dis2+=ib-ia;else dis1+=ia-ib; else if (b>ia) dis2+=b-ia;else dis1+=ia-b; if (dis1!=0) dis1-=(ia-st[aa].l);dis1+=a-st[ya].l; if (flag!=0) dis2-=(ib-st[aa].l),dis2+=b-st[yb].l;//else dis2=b-ia; if (0==flag) ib=b; if (pd) e=ia,ia=ib,ib=e,e=dis1,dis1=dis2,dis2=e; if (dis1==dis2) return min(ia,ib); if (dis1>dis2) return make(oa,(dis1+dis2)/2); else { k=(dis1+dis2)/2; if (((dis1+dis2)&1)==1) k++; return make(ob,k); } }