码迷,mamicode.com
首页 > 其他好文 > 详细

【NOIP模拟】Angel Beats!

时间:2016-07-19 10:10:51      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:

Description

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

Solution

crazy_czy很喜欢这部番……卖广告
看到这题很懵逼啊,一个点x到他所在的子树y的所有节点的距离和怎么求,这个很简单,正难则反:
x=x?x
=x??(n?)×dist(x,y)
=x?(?)?(n?)×dist(x,y)
但是现在问题来了,怎么预处理出每个子树的重心?????
然后我这题就爆零了。
crazy_czy用了一大堆性质给我们讲。
1线
2size
2xsizeysize(x)?1?size(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);
    }
}

【NOIP模拟】Angel Beats!

标签:

原文地址:http://blog.csdn.net/doyouseeman/article/details/51939202

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!