【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); } }
相关文章推荐
- ssm整合
- java设计模式之工厂模式
- 8086汇编语言自学经验分享 如何将一个段设置为代码段,数据段,栈段
- linux笔记:linux常用命令-目录和文件处理命令
- ExtJS-服务器代理
- 【记录】ldr
- CodeForces 131C--组合数
- 利用函数返回oracle对象表的三种方法
- 线性布局
- js中变量类型判断
- iOS开发-javaScript交互
- [JQ权威指南]$.ajax()方法发送请
- spring源码分析之定时任务Scheduled注解
- 远程办公
- sql连接查询
- 整数中1出现的次数(从1到n整数中1出现的次数) java
- Yii2简单实现给表单添加验证码的方法
- 【记录】dd
- Django's URL Configuration String View in 1.10+
- org.apache.poi.hssf.usermodel.HSSFWorkbook和org.apache.poi.xssf.usermodel.XSSFWorkbook的区别