题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5354
题意:求删去每个点后图是否存在奇环(n,m<=1e5)
解法:很经典的套路,和这题一样:http://www.cnblogs.com/spfa/p/7358672.html CDQ套并查集。 这题最开始是看了南神的代码才懂的,http://blog.csdn.net/hdu2014/article/details/47450709 因为要判断每一个点,而且一旦一个点之外的几个点形成了奇环的话这个点一定就是No,所以用分治来解。先判断每一段之外的点是否会成为奇环,如果是的话,这一段就全是No,反之就把这些点放到并查集里并记录,然后分治当前段,直到分治进行到单个点,分治结束后把并查集还原。真是神奇的分治。orz
//HDU 5354 #include <bits/stdc++.h> using namespace std; typedef pair<int,int>pi; const int maxn = 400020; vector<pi>E[maxn*2]; int n,m,f[maxn],sz[maxn],val[maxn],ans[maxn]; bool in(int a, int L, int R){ return a>=L&&a<=R; } void solve(int l, int r, int x, vector<pi>&tp); pi find_set(int x){ int ret=x; int w=0; for(;f[ret]!=ret;ret=f[ret]) w^=val[ret]; w^=val[ret]; return pi(ret,w); } void CDQ(int l, int r, int x){ if(l == r){ ans[l]=1; return; } E[x<<1].clear(); E[x<<1|1].clear(); vector<pi>tp[2]; int mid = (l+r)>>1; for(int i=0; i<E[x].size(); i++){ int a=E[x][i].first,b=E[x][i].second; if(in(a,l,mid)||in(b,l,mid)) E[x<<1].push_back(E[x][i]); else tp[0].push_back(E[x][i]); if(in(a,mid+1,r)||in(b,mid+1,r)) E[x<<1|1].push_back(E[x][i]); else tp[1].push_back(E[x][i]); } solve(l,mid,x<<1,tp[0]); solve(mid+1,r,x<<1|1,tp[1]); } void solve(int l, int r, int x, vector<pi>&tp) { vector<pi>res; bool flag=0; for(int i=0; i<tp.size(); i++){ int u=tp[i].first,v=tp[i].second; pi fu = find_set(u), fv = find_set(v); if(fu.first==fv.first){ if(!(fu.second^fv.second)){ flag = 1; break; } } else{ int t1=sz[fu.first]>sz[fv.first]?fu.first:fv.first; int t2=fu.first+fv.first-t1; int t3=fu.second^fv.second; f[t2]=t1; sz[t1]+=sz[t2]; res.push_back(pi(t2,t3)); val[t2]^=t3; } } if(flag){ for(int i=l; i<=r; i++) ans[i]=0; } else CDQ(l,r,x); for(int i=res.size()-1; i>=0; i--){ int u=res[i].first; sz[f[u]]-=sz[u]; val[u]^=res[i].second; f[u]=u; } } int main() { int T; scanf("%d", &T); while(T--) { E[1].clear(); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) f[i]=i,sz[i]=1,val[i]=1; for(int i=1; i<=m; i++){ int u,v; scanf("%d%d",&u,&v); if(u>v) swap(u,v); E[1].push_back(pi(u,v)); } CDQ(1,n,1); for(int i=1; i<=n; i++) printf("%d",ans[i]); printf("\n"); } return 0; }
时间: 2024-08-01 20:32:23