缩点+树上差分——Codeforces555E Case of Computer Network
2017-10-21 07:44
239 查看
题面:cf555e
简要题意:给出一个无向图,给出q个询问S,T表示从S走到T。问能否给这张图的边定向,使得满足q个询问
我们首先发现对于每一个边双连通分量,两两之间是可以随便到达的,包括去到外面的点。所以我们把边双都缩成一个点,这张图就变成了一棵树
对于树进行操作就简单多了,我们只要在S,T,LCA位置打上差分标记(S打向上,T打向下,LCA打消除),然后一遍dfs从下往上扫一遍,如果某个节点向下向上标记都存在的话,这条边就发生冲突了
简要题意:给出一个无向图,给出q个询问S,T表示从S走到T。问能否给这张图的边定向,使得满足q个询问
我们首先发现对于每一个边双连通分量,两两之间是可以随便到达的,包括去到外面的点。所以我们把边双都缩成一个点,这张图就变成了一棵树
对于树进行操作就简单多了,我们只要在S,T,LCA位置打上差分标记(S打向上,T打向下,LCA打消除),然后一遍dfs从下往上扫一遍,如果某个节点向下向上标记都存在的话,这条边就发生冲突了
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <iostream> #include <ctime> #include <map> #include <queue> #include <cstdlib> #include <string> #include <climits> #include <set> #include <vector> using namespace std; inline int read(){ int k=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();} return k*f; } int nedge=0,p[400010],nex[400010],head[400010]; int nedge1=0,p1[400010],nex1[400010],head1[400010]; int dfn[200010],low[200010],s[200010],d[200010],l[200010]; int n,m,q,cnt=0,Top=0,vis[200010]; int deep[200010],f[200010],son[200010],top[200010]; int fa[200010],rp[200010][2],b[200010]; inline int getfather(int x){return fa[x]==x?x:fa[x]=getfather(fa[x]);} inline void addedge(int a,int b){ p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge; } inline void addedge1(int a,int b){ p1[++nedge1]=b;nex1[nedge1]=head1[a];head1[a]=nedge1; } inline void tarjan(int x,int fa){ dfn[x]=low[x]=++cnt; s[++Top]=x;bool r=1;b[x]=1; for(int k=head[x];k;k=nex[k]){ if(p[k]==fa&&r){ r=0;continue; } if(!dfn[p[k]])tarjan(p[k],x),low[x]=min(low[x],low[p[k]]); else if(b[p[k]])low[x]=min(low[x],dfn[p[k]]); } if(dfn[x]==low[x]){ d[0]++;int k=0; do{ k=s[Top--];d[d[0]]++;l[k]=d[0];b[k]=0; }while(k!=x); } } inline void dfs(int x,int fat,int dep){ vis[x]=1; deep[x]=dep;s[x]=1;f[x]=fat; for(int k=head1[x];k;k=nex1[k])if(p1[k]!=fat){ dfs(p1[k],x,dep+1);s[x]+=s[p1[k]]; if(s[p1[k]]>s[son[x]])son[x]=p1[k]; } } inline void dfss(int x,int t){ top[x]=t; if(son[x])dfss(son[x],t); for(int k=head1[x];k;k=nex1[k])if(p1[k]!=f[x]&&p1[k]!=son[x])dfss(p1[k],p1[k]); } inline int lca(int x,int y){ int fx=top[x],fy=top[y]; while(fx!=fy){ if(deep[fx]<deep[fy])swap(fx,fy),swap(x,y); x=f[fx];fx=top[x]; } if(deep[x]>deep[y])swap(x,y);return x; } inline void DFS(int x){ vis[x]=2; for(int k=head1[x];k;k=nex1[k]){ int to=p1[k]; if(to==f[x])continue; DFS(to);rp[x][0]+=rp[to][0];rp[x][1]+=rp[to][1]; } if(rp[x][0]*rp[x][1]){puts("No");exit(0);} } int main() { n=read();m=read();q=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); addedge(x,y);addedge(y,x); } for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0); for(int i=1;i<=d[0];i++)fa[i]=i; for(int i=1;i<=n;i++) for(int k=head[i];k;k=nex[k])if(l[i]!=l[p[k]]){ addedge1(l[i],l[p[k]]); int fx=getfather(l[i]),fy=getfather(l[p[k]]); fa[fx]=fy; } n=d[0]; for(int i=1;i<=n;i++)if(!vis[i]){ dfs(i,0,1);dfss(i,i); } for(int i=1;i<=q;i++){ int x=l[read()],y=l[read()]; int fx=getfather(x),fy=getfather(y); if(fx!=fy)return puts("No")&0; int LCA=lca(x,y); rp[x][0]++;rp[y][1]++;rp[LCA][0]--;rp[LCA][1]--; } for(int i=1;i<=n;i++)if(vis[i]!=2)DFS(i); puts("Yes"); return 0; }
相关文章推荐
- 树状网络攻击(LCA和树上差分的应用)
- NOIP2016 Day2 T2 天天爱跑步(树上差分)
- BZOJ 3631 [JLOI2014]松鼠的新家 | 树上差分
- ☆ [NOIp2016] 天天爱跑步 「树上差分」
- poj3417 闇の連鎖 【树上差分】By cellur925
- 【NOIP2015】运输计划 {二分答案+倍增+树上差分}
- 【NOIP2016提高组T2】天天爱跑步-倍增LCA+树上差分
- bzoj 4326 运输计划 (树链剖分 + 树上差分 + 二分)
- 树上的差分
- noip运输计划(倍增lca,树上差分)
- 【BZOJ3626】LCA(树上差分,树链剖分)
- [BZOJ4326][NOIP2015]运输计划(二分答案+树上差分)
- P2680 运输计划(二分+树上差分)
- 【结论】【树上差分】
- 树上差分
- 【bzoj 4390】 [Usaco2015 dec]Max Flow(树上差分)
- NOIP模拟题 [DP][二分][树剖][树上差分]
- 【BZOJ 2588】Spoj 10628. Count on a tree 主席树+树上差分
- LCA+二分+树上差分——Luogu2680 [NOIP2015]运输计划
- 【省选模拟试题】压力 点双连通分量缩点+树上差分