wc上第一次听这个题就感觉很有想法,于是想了个倍增,只能过50分,后来周而进讲了分块存图的方法,可惜只能用动态树维护,经ATM启发,每次分块后都不裂块,以适应倍增的树形态不变的性质,也就是后来钟沛林讲的方法,实现起来还比较容易,只是细节难以处理。
每个块我只存块状树深度,左右端点,每要处理一个点,二分其所处的块,倍增存2^k步的块,2^k步的点,2^k到块顶的距离,然后各种特判维护实际距离。
#include
#include
#include
#include
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=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 (ab)&&((a+b)%2==1)) k++;return k;}
if (st[aa].d>=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 (iaia) 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);
}
}