[bzoj4025]二分图_LCT
二分图 bzoj-4025
题目大意:给定一个n个节点的图,m条边,每条边有一个产生时间和一个删除时间,询问所有时间点是否是连通图。
注释:$1\le n\le 10^5$,$1\le m\le 2\cdot 10^5$
想法:好难...
又是一道结论题。开始不知道结论,在那里LCT不知道怎么判二分图... ...
其实就是判每一个时刻有没有奇环... ...硬核题...
紧接着,我们考虑如何维护。
我们先随便弄出一棵生成树,然后我们想维护这样的集合S。S中的任意一条边都会和生成树构成奇环。
有一种情况我们没有办法处理,就是把集合的边加上,然后... ...树边没了,我们还要把集合中的边换成树边,非常麻烦,码量堪忧。
所以,我们要维护最大删除时间生成树,就不会出现以上情况。
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define ls ch[p][0] #define rs ch[p][1] #define get(x) (ch[f[x]][1]==x) #define N 100010 using namespace std; struct Node { int x,y,t1,t2; }a[N<<1]; int n,f[N<<2],ch[N<<2][2],size[N<<2],w[N<<2],mp[N<<2],rev[N<<2],num[N]; int sum,now; inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read() { int ret=0; char ch=nc(); while(!isdigit(ch)) ch=nc(); while(isdigit(ch)) ret=(ret<<3)+(ret<<1)+ch-48,ch=nc(); return ret; } inline bool cmp(const Node &a,const Node &b) { return a.t1<b.t1; } inline void pushup(int p) { size[p]=size[ls]+size[rs]+1; mp[p]=p; if(w[mp[ls]]<w[mp[p]]) mp[p]=mp[ls]; if(w[mp[rs]]<w[mp[p]]) mp[p]=mp[rs]; } inline void pushdown(int p) { if(!rev[p]) return; swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]); rev[ls]^=1; rev[rs]^=1; rev[p]=0; } inline bool isroot(int p) { return ch[f[p]][0]!=p&&ch[f[p]][1]!=p; } void update(int p) { if(!isroot(p)) update(f[p]); pushdown(p); } void rotate(int x) { int y=f[x],z=f[y],k=get(x); if(!isroot(y)) ch[z][ch[z][1]==y]=x; ch[y][k]=ch[x][!k]; f[ch[y][k]]=y; ch[x][!k]=y; f[y]=x; f[x]=z; pushup(y); pushup(x); } void splay(int x) { update(x); for(int t;t=f[x],!isroot(x);rotate(x)) { if(!isroot(t)) rotate(get(x)==get(t)?t:x); } } void access(int p) { int t=0; while(p) splay(p),rs=t,pushup(p),t=p,p=f[p]; } int find(int p) { access(p),splay(p); while(ls) pushdown(p),p=ls; return p; } inline void makeroot(int p) { access(p),splay(p); swap(ls,rs),rev[p]^=1; } inline void link(int x,int y) { makeroot(x),f[x]=y; } inline void cut(int x,int p) { makeroot(x),access(p),splay(p); f[x]=ls=0;pushup(p); } inline void split(int x,int y) { makeroot(x),access(y),splay(y); } void add(int p) { int tx=a[p].x,ty=a[p].y,tmp,flag=0; if(tx==ty&&a[p].t2>now) num[a[p].t2]++,sum++; else { if(find(tx)!=find(ty)) link(p+n,tx),link(ty,p+n); else { split(tx,ty); if(!((size[ty]>>1)&1)) flag=1; if(w[mp[ty]]>=a[p].t2) tmp=p; else tmp=mp[ty]-n,cut(tmp+n,a[tmp].x),cut(tmp+n,a[tmp].y),link(p+n,tx),link(p+n,ty); if(flag&&a[tmp].t2>now) num[a[tmp].t2]++,sum++; } } } int main() { int m,t,p=1; n=read(),m=read(),t=read(); for(int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].t1=read(),a[i].t2=read(); sort(a+1,a+m+1,cmp); for(int i=1;i<=n+m;i++) size[i]=1,mp[i]=i; for(int i=0;i<=n;i++) w[i]=1<<30; for(int i=1;i<=m;i++) w[i+n]=a[i].t2; for(int i=0;i<t;i++) { now=i; while(p<=m&&a[p].t1<=i) add(p),p++; sum-=num[i]; if(sum) puts("No"); else puts("Yes"); } return 0; }
小结:LCT就是强。
| 欢迎来原网站坐坐! >原文链接<