bzoj4025: 二分图
bzoj4025: 二分图
博主回归啦,懒得开小号了
神仙的一批。。。只会LCT,瑟瑟发抖
首先用LCT维护一棵树,把边加和删的时间点拿出来sort一遍就变成了加边和删边操作
如果要加进去一条边的时候发现这两点还没有联通就直接LCT上连边;要删的话如果在LCT上就在LCT上删边
如果发现这条边会构成奇环(后面叫它“奇环边”)就不是二分图了,把这条边单独放在一个地方存起来(set),要删的时候从那里删
每个时刻末尾,当没有奇环边的时候输出Yes,有就输出No
然后发现很麻烦不好处理,因为从LCT上删边之后,一些奇环边就不再是奇环边了,可以重新回到LCT,但这个很不好维护,所以要保证在LCT上删边的时候没有一条奇环边对它有影响
把边权设为这条边要删除的时间,维护最大生成树,每次要加新边的时候如果这两点已经联通就尝试消圈
如果一条边加入会构成奇环,这条边又通过消圈进入了LCT,要把消掉的那条边加入奇环集合
就能保证LCT上的边删除时奇环边集合不会对LCT有影响
然后代码异常丑陋:
#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
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*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=300100;
struct edge{int u,v,t,ed,o,id;}E[400100];
il bool operator <(const edge&a,const edge&b){
if(a.t^b.t)return a.t<b.t;
else return a.o==-1;
}
int ch[maxn][2],fa[maxn],siz[maxn],w[maxn],mn[maxn];bool rev[maxn];
int A[maxn],B[maxn];
il vd Rev(int x){if(x)std::swap(ch[x][0],ch[x][1]),rev[x]^=1;}
il bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
il vd upd(int x){
if(x){
siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
mn[x]=x;
if(w[mn[ch[x][0]]]<w[mn[x]])mn[x]=mn[ch[x][0]];
if(w[mn[ch[x][1]]]<w[mn[x]])mn[x]=mn[ch[x][1]];
}
}
il vd down(int x){
if(x==0)return;
if(!isrt(x))down(fa[x]);
if(rev[x])Rev(ch[x][0]),Rev(ch[x][1]),rev[x]=0;
}
il vd rotate(int x){
int y=fa[x],z=fa[y],o=x==ch[y][1];
fa[x]=z;if(!isrt(y))ch[z][y==ch[z][1]]=x;
ch[y][o]=ch[x][!o];fa[ch[x][!o]]=y;
fa[y]=x;ch[x][!o]=y;
upd(y);
}
il vd splay(int x){
if(x==0)return;
down(x);
for(int y=fa[x],z=fa[y];!isrt(x);rotate(x),y=fa[x],z=fa[y])
if(!isrt(y))rotate(((x==ch[y][0])!=(y==ch[z][0]))?x:y);
upd(x);
}
il vd access(int x){for(int y=0;x;x=fa[y=x])splay(x),ch[x][1]=y,upd(x);}
il vd makert(int x){access(x),splay(x),Rev(x);}
il vd link(int x,int y){
makert(x);fa[x]=y;
}
il vd cut(int x,int y){
makert(x),access(y),splay(y);ch[y][0]=fa[x]=0;
}
il std::pair<int,int> dist(int x,int y){
makert(x),access(y),splay(y);
int z=y;while(ch[z][0])z=ch[z][0];
if(z!=x)return std::make_pair(-1,-1);
else return std::make_pair(siz[y]-1,mn[y]);
}
std::set<int>edgeList;
bool yes[maxn];
int main(){
int n=gi(),m=gi(),T=gi(),cnt=0;
for(int i=1;i<=m;++i){
int u=gi(),v=gi(),st=gi()+1,ed=gi()+1;
if(st==ed)continue;
E[++cnt]=(edge){u,v,st,ed,1,i};
E[++cnt]=(edge){u,v,ed,ed,-1,i};
}
std::stable_sort(E+1,E+cnt+1);
int p=1;
for(int i=0;i<=n;++i)w[i]=1e9;
for(int t=1;t<=T;++t){
while(p<=cnt&&E[p].t<=t){
if(E[p].o==-1){
std::set<int>::iterator it=edgeList.find(E[p].id);
if(it!=edgeList.end())edgeList.erase(it);
else if(!yes[E[p].id])cut(E[p].u,n+E[p].id),cut(E[p].v,n+E[p].id);
}else{
std::pair<int,int> d=dist(E[p].u,E[p].v);
if(E[p].u==E[p].v)edgeList.insert(E[p].id);
else if(d.first==-1){
int x=E[p].id+n;
w[x]=E[p].ed;
link(A[x]=E[p].u,x),link(B[x]=E[p].v,x);
}
else if(w[d.second]<E[p].ed){
int x=n+E[p].id;
w[x]=E[p].ed;
cut(d.second,A[d.second]),cut(d.second,B[d.second]);
if(d.first%4==2)yes[d.second-n]=1;
else edgeList.insert(d.second-n);
A[x]=E[p].u,B[x]=E[p].v;
link(x,A[x]),link(x,B[x]);
}
else if(d.first%4==0)edgeList.insert(E[p].id);
else yes[E[p].id]=1;
}
++p;
}
if(edgeList.empty())puts("Yes");
else puts("No");
}
return 0;
}
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。