http://www.elijahqi.win/2018/02/12/bzoj4025/
Description
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。
Input
输入数据的第一行是三个整数n,m,T。
第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。
Output
输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。
Sample Input
3 3 3
1 2 0 2
2 3 0 3
1 3 1 2
Sample Output
Yes
No
Yes
HINT
样例说明:
0时刻,出现两条边1-2和2-3。
第1时间段内,这个图是二分图,输出Yes。
1时刻,出现一条边1-3。
第2时间段内,这个图不是二分图,输出No。
2时刻,1-2和1-3两条边消失。
第3时间段内,只有一条边2-3,这个图是二分图,输出Yes。
数据范围:
n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。
题意:略
二分图性质 不存在奇环的图
首先将所有边读入 按照开始出现的时间排序 按照出现的时间依次添加 那么我们可以知道 当我这个环上最早消失的那条边消失之后我的这个奇环也就不复存在了 那么不妨针对每个事件我开一个桶 存入这个时间一共有多少条这样的边 然后过了这个时间后就把这条边的影响消除掉即可 最后在回答询问的时候看一看全图是否还存在这样的奇边 根据这个情况回答即可 那相当于我需要维护一个以消失时间为权值的最大生成树 针对做每条边的时候 如果形成奇环 那么我就将这这条边消失时间插入桶内关于 边权如何用lct维护 参考noi2014魔法森林 将边权重新建一个新点判断是否是奇环 直接把这条链提取出来看一下size即可 一开始我以为find之后就不需要每次splay都要下放 其实仍然需要 注意判断自环的情况 更新的时候我们每次在链上找一个最小点 如果我这个边比最小边要大 那么就更新最小边
我好菜qwq vjudge上tle了一页
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 440000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if(T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S)return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int x,y,st,ed;
}data[N>>1];
int c[N][2],size[N],fa[N],bl[N],v[N],rev[N],num[N>>2],n,m,T,sum,top,q[N];
inline bool cmp(const node &a,const node &b){return a.st<b.st;}
inline void update(int x){
int l=c[x][0],r=c[x][1];bl[x]=x;
size[x]=size[l]+size[r]+1;
if (v[bl[l]]<v[x]) bl[x]=bl[l];
if (v[bl[r]]<v[bl[x]]) bl[x]=bl[r];
}
inline void pushdown(int x){
if (!rev[x]) return;rev[x]=0;
int l=c[x][0],r=c[x][1];
swap(c[x][0],c[x][1]);rev[l]^=1;rev[r]^=1;
}
inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
inline void rotate(int x){
int y=fa[x],z=fa[y];
if (!isroot(y)) c[z][c[z][1]==y]=x;
int l=c[y][1]==x,r=l^1;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x){
q[top=1]=x;for (int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if (!isroot(y)) if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);
rotate(x);
}
}
inline void access(int x){for (int t=0;x;t=x,x=fa[x]) splay(x),c[x][1]=t,update(x);}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}
inline int find(int x){access(x);splay(x);while(c[x][0]) pushdown(x),x=c[x][0];return x;}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void cut(int x,int y){makeroot(x);access(y);splay(y);fa[x]=c[y][0]=0;update(y);}
int main(){
//freopen("bzoj4025.in","r",stdin);
n=read();m=read();T=read();
for (int i=1;i<=m;++i) data[i].x=read(),data[i].y=read(),data[i].st=read(),data[i].ed=read();
sort(data+1,data+m+1,cmp);int now=1;for (int i=0;i<=n;++i) v[i]=0x3f3f3f3f;
for (int i=1;i<=n+m;++i) size[i]=1,bl[i]=i;for (int i=1;i<=m;++i) v[i+n]=data[i].ed;
for (int t=0;t<T;++t){
while(now<=m&&data[now].st<=t){
int x=data[now].x,y=data[now].y,tmp;bool flag=0;
if (x==y) {if(data[now].ed>t) ++num[data[now].ed],++sum;++now;continue;}
if (find(x)!=find(y)) {link(now+n,x),link(now+n,y);++now;continue;}
makeroot(x);access(y);splay(y);if(!((size[y]>>1)&1)) flag=1;
if (v[bl[y]]>=data[now].ed) tmp=now;else
tmp=bl[y]-n,cut(tmp+n,data[tmp].x),cut(tmp+n,data[tmp].y),link(now+n,x),link(now+n,y);
if(data[tmp].ed>t&&flag) ++num[data[tmp].ed],++sum;++now;
}
sum-=num[t];
if (!sum) puts("Yes");else puts("No");
}
return 0;
}