【NOIP模拟】Angel Beats!

来源:互联网 发布:推女郎吧最新域名 编辑:程序博客网 时间:2024/04/29 17:47

Description

天使立华奏攻入了死后世界战线(SSS)的地下工会Guild,这是万分危急的时候。仲村由理指挥工会成员有条不紊地进行撤退工作。工会成员在Guild最深层工厂安放炸药需要很长的准备时间,需要有人来拖延立华奏的前进速度。但是他们并不清楚立华奏的具体位置,因此他们需要设立许多个防御点。
Guild的结构可以看成一棵有n 个节点的树,有时由理会得到立华奏的大概位置,可能在某两棵子树的任意一棵中,她就会找到Guild树(不一定要在两棵子树内)上的一个点,使得该点到两棵子树中所有点距离之和最小,即这两棵子树的重心(如果两棵子树有重合部分,那么取它们并集求重心)。
具体而言,你会得到Guild的结构(1为根),然后会有q个询问,向你查询点x子树和点y子树的重心,重心可能会有很多个,你只需要输出距离和即可。

Solution

crazy_czy很喜欢这部番……卖广告
看到这题很懵逼啊,一个点x到他所在的子树y的所有节点的距离和怎么求,这个很简单,正难则反:
x=xx
=x(n)×dist(x,y)
=x()(n)×dist(x,y)
但是现在问题来了,怎么预处理出每个子树的重心?????
然后我这题就爆零了。
crazy_czy用了一大堆性质给我们讲。
1线
2size
2xsizeysize(x)1size(y)size(y)xxy
结论2的推论证明十分的机制,因为如果size(x)-size(y)-1≥size(y),就说明重心不在最大的那个子数里面而在其他的子树的集合里面,那么最大的子树不符合,其他任意的子树也是同样的情况,那么最后所有子树集合的交际就是根节点x。
虽然知道了这些,代码———-
但是还是搞了很久,当时我向上倍增找重心一直找错,后来改了个巧妙的倍增。
本来倍增我存了很多什么最小值啊,位置啊之内的,然后其实每次倍增满足

    size[y]-size[f[x][i]]>size[y]/2&&deep[f[x][i]]>deep[y]

这段东西就可以了,然后

if(size[y]-size[f[x][0]]<=size[y]/2&&size[big[f[x][0]]]<=size[y]/2)return f[x][0];return x;

在往上跳一位就是重心了。
表示调了好久……

Code

#include<iostream>#include<cstdio>#include<cstring>#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;const int maxn=100007;int i,j,k,l,t,n,m,ans;int first[maxn*2],next[maxn*2],last[maxn*2],num,bb,cc; int f[maxn][21],deep[maxn],g[maxn][21],size[maxn],zhong[maxn],big[maxn],wei[maxn][21],sum[maxn],zs[maxn];void add(int x,int y){    last[++num]=y;next[num]=first[x];first[x]=num;    last[++num]=x;next[num]=first[y];first[y]=num;}/*int lca(int x,int y){    bb=0x7fffffff;cc=0;    int i;    if(deep[x]<deep[y])swap(x,y);    fod(i,20,0)if(deep[f[x][i]]>deep[y])cc=(g[x][i]<bb)?wei[x][i]:cc,bb=min(bb,g[x][i]),x=f[x][i];    if(deep[x]!=deep[y])cc=(g[x][0]<bb)?wei[x][0]:cc,bb=min(bb,g[x][i]),x=f[x][0];    fod(i,20,0)if(f[x][i]!=f[y][i])cc=(g[x][i]<bb)?wei[x][i]:cc,bb=min(g[x][i],bb),cc=(g[y][i]<bb)?wei[y][i]:cc,bb=min(g[y][i],bb),x=f[x][i],y=f[y][i];    if(x!=y)cc=(g[x][0]<bb)?wei[x][0]:cc,bb=min(g[x][0],bb),cc=(g[y][0]<bb)?wei[y][0]:cc,bb=min(g[y][0],bb);    if(x!=y)return f[x][0];return x;}*/int lca(int x,int y){    int i,k=0x7fffffff;    if(deep[x]<deep[y])swap(x,y);    fod(i,20,0)    if(deep[f[x][i]]>deep[y])    bb=(g[x][i]<k?wei[x][i]:bb),k=min(k,g[x][i]),x=f[x][i];        if(deep[x]!=deep[y])bb=(g[x][0]<k?wei[x][0]:bb),k=min(k,g[x][0]),x=f[x][0];    fod(i,20,0)if(f[x][i]!=f[y][i])bb=(g[x][i]<k?wei[x][i]:bb),k=min(k,g[x][i]),bb=(g[y][i]<k?wei[y][i]:bb),k=min(k,g[y][i]),x=f[x][i],y=f[y][i];    if(x!=y)bb=(g[x][0]<k?wei[x][0]:bb),k=min(k,g[x][0]),bb=(g[y][0]<k?wei[y][0]:bb),k=min(k,g[y][0]);    if(x!=y)return f[x][0];else return x;}int bei(int x,int y){    int i,k=0x7fffffff;    if(deep[x]<deep[y])swap(x,y);    fod(i,20,0)if(size[y]-size[f[x][i]]>size[y]/2&&deep[f[x][i]]>deep[y])x=f[x][i];    if(size[y]-size[f[x][0]]<=size[y]/2&&size[big[f[x][0]]]<=size[y]/2/*&&deep[f[x][0]]>deep[y]*/)return f[x][0];return x;}void dfs(int x,int y){    int i,k=0;    deep[x]=deep[y]+1;size[x]=1;    sum[1]+=deep[x]-1;    if(x==38){        ans=ans;    }    rep(i,x){        if(last[i]!=y){            dfs(last[i],x);            size[x]+=size[last[i]];            if(size[last[i]]>k){                k=size[last[i]];                big[x]=last[i];            }            zs[x]+=zs[last[i]]+size[last[i]];        }    }}void dfs1(int x,int y){    int i,o=n-size[x];    g[x][0]=sum[x];wei[x][0]=x;    if(x==38){        ans=ans;    }    rep(i,x){        if(last[i]!=y){            sum[last[i]]=sum[x]+(n-size[last[i]])-size[last[i]];            dfs1(last[i],x);        }    }}void fh(int x,int y){    int i,o=n-size[x];    rep(i,x){        if(last[i]!=y){            fh(last[i],x);        }    }    if(size[x]==1){        zhong[x]=x;        return;    }    if(x==38){        ans=ans;    }    if(size[big[x]]<=size[x]-size[big[x]]-1)zhong[x]=x;    else{    /*  if(size[x]-size[zhong[big[x]]]<=size[x]/2){            zhong[x]=zhong[big[x]];        }        else{*/            int o=bei(zhong[big[x]],x);            zhong[x]=o;            //    }    }}int suan(int x,int y){    int o=0;    o=sum[x]-(sum[y]-zs[y])-(n-size[y])*(deep[x]-deep[y]);}int main(){//  freopen("fan.out","w",stdout);    scanf("%d",&n);    fo(i,2,n){        scanf("%d",&f[i][0]);        add(f[i][0],i);    }    dfs(1,0);    memset(g,127,sizeof(g));    dfs1(1,0);    fo(j,1,20){        fo(i,1,n){            f[i][j]=f[f[i][j-1]][j-1];            wei[i][j]=(g[i][j-1]<g[f[i][j-1]][j-1])?wei[i][j-1]:wei[f[i][j-1]][j-1];            g[i][j]=min(g[i][j-1],g[f[i][j-1]][j-1]);        }    }    fh(1,0);    for(scanf("%d",&m);m;m--){        scanf("%d%d",&k,&l);        int o=lca(k,l);int u=deep[k]-2*deep[o]+deep[l];int ss=size[k]+size[l];        if(size[k]<size[l])swap(k,l);        if(k==o)ss=size[k];        int z=zhong[k];        fod(i,20,0)if(ss-size[f[z][i]]>ss/2&&deep[f[z][i]]>deep[k])z=f[z][i];        if(ss-size[f[z][0]]<=ss/2&&size[big[f[z][0]]]<=ss/2/*&&deep[f[z][0]]>=deep[k]&&deep[f[z][0]]>deep[o]*/)z=f[z][0];        if(k==o)ans=suan(z,k);        else ans=suan(z,k)+(u+deep[z]-deep[k])*size[l]+zs[l];        printf("%d\n",ans);    }}
1 0
原创粉丝点击