您的位置:首页 > 其它

【NOIP模拟】Angel Beats!

2016-07-18 09:33 302 查看

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:两棵子树的重心一定在两棵子树各自重心连线的路径上。

结论2:在两棵子树size较大那棵内部一定能找到两棵子树重心。

结论2的推论:对于一个点x,令其size最大儿子为y,如果size(x)−1−size(y)≥size(y),那么子树x的重心一定为x,否则就一定在点y的子树内

结论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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: