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);
}
}