HDU3896 Greatest TC(双联通分量+倍增)
Problem Description
TC (Tian Chao) is magical place, as you all know...
The railways and the rail-stations in TC are fragile and always meet with different kinds of problems. In order to reach the destination safely on time, you are asked to develop a system which has two types of main functions as below.
1: A B C D, reporting whether we can get from station A to station B without passing the railway that connects station C and station D.
2: A B C, reporting whether we can get from station A to station B without passing station C.
Please notice that the railways are UNDIRECTED.
The railways and the rail-stations in TC are fragile and always meet with different kinds of problems. In order to reach the destination safely on time, you are asked to develop a system which has two types of main functions as below.
1: A B C D, reporting whether we can get from station A to station B without passing the railway that connects station C and station D.
2: A B C, reporting whether we can get from station A to station B without passing station C.
Please notice that the railways are UNDIRECTED.
Input
For each test case, the first line will contain two integers N (2<=N<=100000) and M (1<=M<=500000), namely the number of stations and railways in TC. Then each of the next M lines will have two integers, describing the two stations that a certain railway is connecting. After this, there comes a line containing a single integer Q (Q<=300000), which means the number of queries to make on the system. The next Q lines will be queries. Each query begins with a integer, indicating the type of query, followed by 4 (the first type) or 3 (the second type) integers describing the details of the query as what mentioned above.
The stations are always labeled from 1 to N.
The stations are always labeled from 1 to N.
Output
For each test case, print "yes" or "no" in separated lines for the queries.
Sample Input
13 15
1 2
2 3
3 5
2 4
4 6
2 6
1 4
1 7
7 8
7 9
7 10
8 11
8 12
9 12
12 13
5
1 5 13 1 2
1 6 2 1 4
1 13 6 7 8
2 13 6 7
2 13 6 8
Sample Output
yes
yes
yes
no
yes
Source
Recommend
题解:
无向图,n个点,m条边;
typ==1:
a,b,c,d : 判断去掉c和d之间的边之后a,b是否联通;
typ==2:
a,b,c:去掉c点之后,a,b是否仍然联通;
思路:先dfs出每个点的dfs序,并处理出每个点的深度以及是否为割点,每条边是否为割边;
对于第一种:(假设c在d的下面)如果a和b一个在c的子树里面,一个不再c的子树里面,并且dc边是桥,则不连通,其他均为联通;
对于第二种:
分成三种情况讨论:
1: a,b都在子树c中,如果a,b在c的同一个儿子当中,那么去掉c是联通的;否则让a,b往上跳,变成c的两个儿子,如果lown(a)>=dfn(c) 或 lown(b)>=dfn(c)成立,那么不连通;
2:a,b只又一个在子树c中,假设a在子树c中,那么,同样让a往上跳,变成c的儿子,.如果lown[a]>=dfn[c],那么不连通,否则联通;
3:a,b都不在子树c中,那么去掉c没有任何影响,所以还是联通(往上跳,可以用倍增法);
参考带码:
#include<bits/stdc++.h> using namespace std; #define mod 10007 #define pii pair<int,int> #define pil pair<int,ll> #define fi first #define se second #define mkp make_pair #define PI acos(-1.0) typedef long long ll; const int INF=0x3f3f3f3f; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } inline ll readll() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } const int maxn=1e5+10; const int maxm=5e5+10; struct Edge{ int u,v; int nxt; } edge[maxm<<1]; int n,m,head[maxn],tot,times; int fa[maxn],dep[maxn],dfn[maxn],out[maxn],lown[maxn]; bool iscut[maxn],isbridge[maxn]; int anc[maxn][20]; inline void AddEdge(int u,int v) { edge[tot].u=u; edge[tot].v=v; edge[tot].nxt=head[u]; head[u]=tot++; } inline void Init() { tot=times=0; memset(head,-1,sizeof(head)); memset(iscut,false,sizeof(iscut)); memset(isbridge,false,sizeof(isbridge)); memset(dep,0,sizeof(dep)); memset(fa,0,sizeof(fa)); } inline void dfs(int u) { dfn[u]=lown[u]=++times; bool flag=false; int child=0; for(int e=head[u];~e;e=edge[e].nxt) { int v=edge[e].v; if(v==fa[u]) continue; if(!dfn[v]) { fa[v]=u; dep[v]=dep[u]+1; dfs(v); lown[u]=min(lown[u],lown[v]); if(lown[v]>=dfn[u]) { iscut[u]=true; if(lown[v]>dfn[u]) isbridge[v]=true; } } else lown[u]=min(lown[u],dfn[v]); } if(u==1 && child==1) iscut[u]=false; out[u]=times; } inline bool subtree(int x,int y) { return (dfn[x]>=dfn[y]&&out[x]<=out[y])?1:0; } inline void preprocess() { memset(anc,0,sizeof(anc)); for(int i=1;i<=n;++i) anc[i][0]=fa[i]; for(int j=1;(1<<j)<n;++j) for(int i=1;i<=n;++i) if(anc[i][j-1]) anc[i][j]=anc[anc[i][j-1]][j-1]; } inline int upward(int u, int x) { for(int i=0;i<20;i++) if((x>>i)&1) u=anc[u][i]; return u; } inline bool Judge(int a,int b,int c) { int in1=subtree(a,c); int in2=subtree(b,c); if(in1&in2) { a=upward(a,dep[a]-dep[c]-1); b=upward(b,dep[b]-dep[c]-1); if(a==b) return true; if(lown[a]>=dfn[c]||lown[b]>=dfn[c]) return false; } if(in1^in2) { if(!in1) swap(a,b); a=upward(a,dep[a]-dep[c]-1); if(lown[a]>=dfn[c]) return false; } return true; } int main() { scanf("%d%d",&n,&m); Init(); int u,v; for(int i=1;i<=m;++i) { u=read(),v=read(); AddEdge(u,v);AddEdge(v,u); } dfs(1);preprocess(); int q=read(); while(q--) { int typ,a,b,c,d; typ=read();a=read();b=read();c=read(); if(typ==1) { d=read(); if(dep[c]<dep[d]) swap(c,d); int temp1=subtree(a,c); int temp2=subtree(b,c); if(isbridge[c]&&(temp1^temp2)) puts("no"); else puts("yes"); } else { bool ok=Judge(a,b,c); if(ok) puts("yes");else puts("no"); } } return 0; }