ShadyPi:鹹魚就要多做水題
阿新 • • 發佈:2018-12-13
二分圖
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。
題解
偶然發現一篇咕咕咕了多年的題解,順手水一波。
這麼好的題當然要用,把出現一條邊看做,消失看做,按時間將操作離線,如果出現了奇環,這就是個二分圖。
但是這是個圖,總有出環的時候,所以我們只在中儲存一個以刪除時間為關鍵值的最大生成樹,時如果出現了環,將刪除時間最早的邊從中刪去,如果形成的是奇環,還要進行標記,奇環數;
刪除時,如果該邊本來就在裡,直接刪去。如果不在裡且為我們標記過的奇環邊,去掉標記,奇環數。
在本時間點的操作全部做完以後,根據奇環數回答詢問即可。
程式碼
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=1e6+5;
struct sd{int op,a1,a2,t,id;};
struct ed{int a1,a2,t;};
bool operator <(sd a,sd b){return a.t<b.t;}
int dad[M],son[M][2],siz[M],mn[M],val[M],n,m,t,top,ans;
bool rev[M],gg[M],on[M];sd ope[M];ed edge[M];
bool notroot(int v){return son[dad[v]][1]==v||son[dad[v]][0]==v;}
void up(int v)
{
siz[v]=(v>n)+siz[ls]+siz[rs];mn[v]=v;
if(val[mn[v]]>val[mn[ls]])mn[v]=mn[ls];
if(val[mn[v]]>val[mn[rs]])mn[v]=mn[rs];
}
void turn(int v){swap(ls,rs);rev[v]^=1;}
void down(int v){if(!rev[v])return;if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}
void push(int v){if(notroot(v))push(dad[v]);down(v);}
void spin(int v)
{
int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f,son[f][k]=w;if(w)dad[w]=f;dad[f]=v,dad[v]=ff;
up(f);
}
void splay(int v){push(v);for(int f,ff;notroot(v);spin(v)){f=dad[v],ff=dad[f];if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);}up(v);}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v);splay(v);turn(v);}
void split(int x,int y){beroot(x);access(y);splay(y);}
void link(int x,int y){beroot(x);dad[x]=y;}
void cut(int x,int y){split(x,y);dad[x]=son[y][0]=0;up(y);}
int findroot(int v){access(v);splay(v);while(ls)push(v),v=ls;return v;}
void in()
{
int a,b,c,d,i;
for(scanf("%d%d%d",&n,&m,&t),memset(val,127,sizeof(val)),i=1;i<=m;++i)
scanf("%d%d%d%d",&a,&b,&c,&d),val[n+i]=d,ope[++top]=(sd){0,a,b,c,i},ope[++top]=(sd){1,a,b,d,i},edge[i]=(ed){a,b,d};
}
void deal1(int x,int y,int id,int lim)
{
int hh;
if(x==y){ans++;gg[id]=1;return;}
beroot(x);
if(findroot(y)!=x){link(y,id+n);link(x,id+n);on[id]=1;return;}
else
{
split(x,y);
if(val[mn[y]]<lim)
{
hh=mn[y]-n;
if(siz[y]&1^1)gg[hh]=1,ans++;
cut(edge[hh].a1,hh+n);cut(edge[hh].a2,hh+n);link(x,id+n);link(y,id+n);
on[hh]=0;on[id]=1;
}
else if(siz[y]&1^1)gg[id]=1,ans++;
}
}
void deal2(int x,int y,int id){if(on[id])cut(x,id+n),cut(y,id+n),on[id]=0;else if(gg[id])gg[id]=0,ans--;}
void ac()
{
sort(ope+1,ope+1+top);
for(int i=0,j=1,x,y,id;i<t;ans?puts("No"):puts("Yes"))
for(++i;ope[j].t<i&&j<=top;++j){x=ope[j].a1,y=ope[j].a2,id=ope[j].id;ope[j].op?deal2(x,y,id):deal1(x,y,id,edge[id].t);}
}
int main(){in();ac();}