[jzoj]3875. 【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)(图论题,构树+缩点+LCA+并查集)
2017-08-21 13:08
555 查看
Description
在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。
但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。
为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。
Input
第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。这些太空隧道按照输入的顺序依次建成。
Output
输出共P行。如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出”No”(不含引号)。
Sample Input
输入1:
3 2 1
1 2
1 3
2 3
输入2:
5 3 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
Sample Output
输出1:
3
输出2:
No
3
2
5
Data Constraint
对于10%的数据有1≤N,M,P≤100;
对于40%的数据有1≤N,M,P≤2000;
对于100%的数据有1≤N,M,P≤200000。
Hint
那么,我们转化思路,题目既然让我们求环的大小,而求环大小肯定会超时,那么是否可以建一个图,让它既不是环,效率又很高呢??
没错,这样一种东西叫做树.
其实这一题我一开始想到的就是并查集,但是由于太naive,一分都没拿到.
想象一下,如果当前我要新加入一条边,在树上的任何一条新加入的边,都会使其形成环,前提是一颗树,而不是森林.
那么,我们每次形成一个环,我可以把它压成一个点,我们可以不使他真的成环,但是我们可以用并查集维护子孙关系,统计一个点它所在环的大小,下次如果再找到这个点,直接用它的环的大小即可.
其实就打一个并查集就好了!–因为我们可以联想到LCA
简单说来,就是把一个环中所有的点都连向LCA,一开始这些点都连向自己.
如果新加入一条边,我们算出这两个点到LCA上所有环的大小,然后就是询问的答案了.
询问完答案之后,我们再把这两个点以及到LCA上的所有点都连向LCA.
这样下一次我们并查集时就可以直接get它的父亲,也就是LCA,然后就可以找到前面计算的结果了.
如果给我们一堆无向边,我们是无法直接确定树的,所以我们可以先把M+P条边一起做,然后直接构出一个树,我们在这个树上再搞,既可以保证答案的正确性,又可以方便操作.
注意,不能只构一遍树,因为有可能是一个森林.
时间复杂度不是很好证,但是感性的理解一下,并查集那种神奇的时间复杂度,是不会超时的.
毕竟n,m,p才200000.
在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。
但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。
为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。
Input
第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。这些太空隧道按照输入的顺序依次建成。
Output
输出共P行。如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出”No”(不含引号)。
Sample Input
输入1:
3 2 1
1 2
1 3
2 3
输入2:
5 3 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
Sample Output
输出1:
3
输出2:
No
3
2
5
Data Constraint
对于10%的数据有1≤N,M,P≤100;
对于40%的数据有1≤N,M,P≤2000;
对于100%的数据有1≤N,M,P≤200000。
Hint
Problem
给定N条原始边,M条新加入的边,每次新连一条边,判断边所连的两点是否处于同一联通分量里,如果是输出这个联通分量的最大大小,如果不是,输出no.Preface
这是一道非常好的图论题.Solution
1.强连通分量,正难则反
首先,第一眼,既然是强连通分量,那肯定会想到Tarjan,可是这题每次跑Tarjan显然是过不了的.那么,我们转化思路,题目既然让我们求环的大小,而求环大小肯定会超时,那么是否可以建一个图,让它既不是环,效率又很高呢??
没错,这样一种东西叫做树.
2.树的应用
在树上维护连通性?想到了什么,没错,并查集.其实这一题我一开始想到的就是并查集,但是由于太naive,一分都没拿到.
想象一下,如果当前我要新加入一条边,在树上的任何一条新加入的边,都会使其形成环,前提是一颗树,而不是森林.
那么,我们每次形成一个环,我可以把它压成一个点,我们可以不使他真的成环,但是我们可以用并查集维护子孙关系,统计一个点它所在环的大小,下次如果再找到这个点,直接用它的环的大小即可.
3、并查集
关键就是如何维护子孙关系,还有环的大小,以及下次询问时,如何找到前面计算的结果.其实就打一个并查集就好了!–因为我们可以联想到LCA
4、LCA–缩点
我们打并查集时,每次连两个点,就把它们所在环都给连起来.简单说来,就是把一个环中所有的点都连向LCA,一开始这些点都连向自己.
如果新加入一条边,我们算出这两个点到LCA上所有环的大小,然后就是询问的答案了.
询问完答案之后,我们再把这两个点以及到LCA上的所有点都连向LCA.
这样下一次我们并查集时就可以直接get它的父亲,也就是LCA,然后就可以找到前面计算的结果了.
5、构树
这题还要注意的一个地方就是,我们如何构树?如果给我们一堆无向边,我们是无法直接确定树的,所以我们可以先把M+P条边一起做,然后直接构出一个树,我们在这个树上再搞,既可以保证答案的正确性,又可以方便操作.
注意,不能只构一遍树,因为有可能是一个森林.
6、时间复杂度
最后,其实打LCA就是为了缩点,一开始我没有想到缩点,于是只有TLE50,后来想到并查集+路径压缩+缩点,就可以效率飞起了.时间复杂度不是很好证,但是感性的理解一下,并查集那种神奇的时间复杂度,是不会超时的.
毕竟n,m,p才200000.
#include <iostream> #include <cstdio> #include <cstring> #define Maxn 400100 using namespace std; int n,m,p,i,j,x,y,xx,yy,w,ans,len,tot; //ans记录环大小,len记录有多少个点被更改 int sx[Maxn],sy[Maxn],fa[Maxn],father[Maxn],grade[Maxn],sum[Maxn],deep[Maxn],d[Maxn],g[Maxn],dep[Maxn]; //fa[i]记录父亲 ,grade[i]记录标号 ,sum[i]表示以grade[i]为编号的环大小. father[i] 用于构图,可以路径压缩! int tov[Maxn],next[Maxn],last[Maxn]; bool flag[Maxn]; int getstep(int x) { if (father[x]==0) return x; father[x]=getstep(father[x]); return father[x]; } int get(int x) { if (fa[x]==0) return x; return get(fa[x]); } int lca(int x,int y) { if ((deep[x]==deep[y]) && (x==y)) return x; if (deep[x]>deep[y]) return lca(fa[x],y); else if (deep[y]>deep[x]) return lca(x,fa[y]); else return lca(fa[x],fa[y]); } void insert(int x,int y) { tov[++tot]=y; next[tot]=last[x]; last[x]=tot; } void dfsdeep(int x) { int k=last[x]; while (k>0) { if (flag[tov[k]]) { fa[tov[k]]=x; flag[tov[k]]=false; d[++len]=tov[k], deep[tov[k]]=deep[x]+1, dfsdeep(tov[k]); } k=next[k]; } } int getfather(int x) { if (g[x]==x) return x; g[x]=getfather(g[x]); return g[x]; } void dfs(int x,int y) { xx=getfather(x); if (flag[ grade[ xx ] ]) { flag[ grade[ xx ] ]=false; d[++len] = grade[ xx ], ans+=sum[ grade[ xx ] ], grade[ xx ]=grade[ y ]; } if (xx==y) return; dfs(fa[x],y); fa[x]=y; g[x]=y; } int main() { scanf("%d%d%d",&n,&m,&p); for (i=1;i<=m+p;i++) { scanf("%d%d",&sx[i],&sy[i]); xx=getstep(sx[i]),yy=getstep(sy[i]); if (xx!=yy) { if (dep[xx]<dep[yy]) father[xx]=yy; else father[yy]=xx; if (dep[xx]==dep[yy]) dep[xx]++; insert(sx[i],sy[i]), insert(sy[i],sx[i]); } } memset(flag,1,sizeof(flag)); for (i=1;i<=n;i++) if (flag[i]) flag[i]=false, deep[i]=1, dfsdeep(i); for (i=1;i<=n;i++) grade[i]=i, g[i]=i, sum[i]=1; memset(flag,1,sizeof(flag)); memset(father,0,sizeof(father)); memset(dep,0,sizeof(dep)); for (i=1;i<=m+p;i++) { x=sx[i],y=sy[i]; xx=getstep(x),yy=getstep(y),len=0; if (xx!=yy) { if (dep[xx]<dep[yy]) father[xx]=yy; else father[yy]=xx; if (dep[xx]==dep[yy]) dep[xx]++; if (i>m) printf("No\n"); } else { xx=getfather(x), yy=getfather(y); w=getfather(lca(xx,yy)),ans=0,len=0; dfs(xx,w); dfs(yy,w); sum[w]=ans; if (i>m) printf("%d\n",ans); } for (j=1;j<=len;j++) flag[d[j]]=true; } }
相关文章推荐
- 【JZOJ3875】【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)
- 【JZOJ3875】【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)
- JZOJ 3875. 【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)
- [jzoj]3874. 【NOIP2014八校联考第4场第2试10.20】准备复赛(exam)(树形DP+组合数)
- jzoj. 3873. 【NOIP2014八校联考第4场第2试10.20】乐曲创作(music)
- 【JZOJ3874】【NOIP2014八校联考第4场第2试10.20】准备复赛(exam)
- 高中OJ3874. 【NOIP2014八校联考第4场第2试10.20】准备复赛(exam)
- 【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)
- 【JZOJ3873】【NOIP2014八校联考第4场第2试10.20】乐曲创作(music)
- 【JZOJ3873】【NOIP2014八校联考第4场第2试10.20】乐曲创作(music)
- 【JZOJ3854】【NOIP2014八校联考第2场第2试9.28】分组(group)
- 【JZOJ3853】【NOIP2014八校联考第2场第2试9.28】帮助Bsny(help)
- 【JZOJ3853】【NOIP2014八校联考第2场第2试9.28】帮助Bsny(help)
- 【JZOJ3871】【NOIP2014八校联考第4场第1试10.19】无聊的游戏(game)
- JZOJ 3871. 【NOIP2014八校联考第4场第1试10.19】无聊的游戏(game)
- 【JZOJ3852】【NOIP2014八校联考第2场第2试9.28】单词接龙(words)
- JZOJ 3870. 【NOIP2014八校联考第4场第1试10.19】单词检索(search)
- JZOJ 3852. 【NOIP2014八校联考第2场第2试9.28】单词接龙(words)
- JZOJ 3871. 【NOIP2014八校联考第4场第1试10.19】无聊的游戏(game)
- {题解}[jzoj3853]【NOIP2014八校联考第2场第2试9.28】帮助Bsny(help)