题意:
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。
题解:
看完题就知道怎么lct……
然而要练习渣的一批的cdq,所以打了cdq+并查集。
对时间分治,假如一条边完全覆盖一个时间段,就加入并查集。
因为只需要知道异或值判偶环,所以直接加权并查集就可以了。
然后开个栈撤销合并操作。
具体代码
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
int sta[200010],top=0;
int n,m,t;
struct node{
int x,y,st,ed;
node(){}
node(int _x,int _y,int _st,int _ed):x(_x),y(_y),st(_st),ed(_ed){}
};
namespace Union_find_set
{
int fa[100010],rank[100010],a[100010];
int findfa(int x)
{
while(fa[x]!=x) x=fa[x];
return x;
}
int dis(int x)
{
int ans=0;
while(fa[x]!=x&&fa[x])
ans^=a[x],x=fa[x];
return ans;
}
void Union(int x,int y,int z)
{
x=findfa(x);y=findfa(y);
if(x==y) return;
if(rank[x]>rank[y]) swap(x,y);
if(rank[x]==rank[y]) rank[y]++,sta[++top]=-y;
fa[x]=y;a[x]=z;sta[++top]=x;
}
void res(int bot)
{
while(top>bot)
{
if(sta[top]<0) rank[-sta[top]]--;
else fa[sta[top]]=sta[top],a[sta[top]]=0;
top--;
}
}
}
void cdq(int l,int r,vector<node> &v)
{
using namespace Union_find_set;
vector<node>::iterator it;
int mid=(l+r)/2,bot=top;
vector<node> L,R;
for(it=v.begin();it!=v.end();it++)
{
if(it->st==l&&it->ed==r)
{
int x=findfa(it->x),y=findfa(it->y);
int z=dis(it->x)^dis(it->y)^1;
if(x!=y) Union(x,y,z);
else if(z&1)
{
for(int i=l;i<=r;i++) printf("No\n");
res(bot);return;
}
}
else if(it->ed<=mid) L.push_back(*it);
else if(it->st>mid) R.push_back(*it);
else L.push_back(node(it->x,it->y,it->st,mid)),R.push_back(node(it->x,it->y,mid+1,it->ed));
}
if(l==r) printf("Yes\n");
else cdq(l,mid,L),cdq(mid+1,r,R);
res(bot);
}
int main()
{
scanf("%d %d %d",&n,&m,&t);
vector<node> v;
node e;
for(int i=1;i<=n;i++) Union_find_set::fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&e.x,&e.y,&e.st,&e.ed);
e.st++;
if(e.st>e.ed) continue;
v.push_back(e);
}
cdq(1,t,v);
}