[動態維護圖連通性] LOJ#122. 【強制線上】動態圖連通性
阿新 • • 發佈:2019-02-13
學一發黑科技
給邊設一個權值,對每一種權值 維護權值大於等於 的邊構成的最大生成樹
加邊
一個邊剛被加入時的權值設為0,如果它連線兩個聯通塊,就把它設為樹邊,否則設為非樹邊
刪邊
假設要刪除邊 ,設它的權值為
如果它是一條非樹邊,直接刪去,否則要找一條邊替代它。
顯然替代它的邊的邊權小於等於
設刪掉這條邊後形成的兩個聯通塊為 和 ,不妨設
那麼就是要找一條邊權小於等於 且連線 和 的邊
暴力列舉所有和 相連的邊就可以了…如果當前列舉到邊是 內部的,把它權值加一,否則結束查詢
用LCT維護複雜都是 的
複雜度證明的話
因為每次最多把一個聯通塊的一半權值加一,而 ,所以 的大小最大為 的一半,那麼層數就是 的
UPD:已被HACK
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <assert.h>
using namespace std;
const int N=5010 ,M=12;
int ttt;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
struct LCT{
struct node{
node *ch[2],*f;
int size,isize,rev;
node(){ size=1; isize=0; ch[0]=ch[1]=f=0;}
}a[N];
inline void Up(node *x){ x->size=(x->ch[0]?x->ch[0]->size:0)+(x->ch[1]?x->ch[1]->size:0)+x->isize+1; }
inline int isl(node *x){ return !x->f || (x->f->ch[0]!=x && x->f->ch[1]!=x); }
inline int dir(node *x){ return x->f && x->f->ch[1]==x; }
inline void rot(node *x){
node *y=x->f,*z=y->f; int wh=dir(x);
if(!isl(y)) z->ch[dir(y)]=x; x->f=z;
if(y->ch[wh]=x->ch[wh^1]) y->ch[wh]->f=y;
(x->ch[wh^1]=y)->f=x; Up(y); Up(x);
}
inline void Push(node *x){
if(!x || !x->rev) return ;
swap(x->ch[0],x->ch[1]);
if(x->ch[0])
x->ch[0]->rev^=1;
if(x->ch[1])
x->ch[1]->rev^=1;
x->rev=0;
}
void Pushtop(node *x){ if(!isl(x)) Pushtop(x->f); Push(x); }
inline void splay(node *x){ Pushtop(x); for(;!isl(x);rot(x))if(!isl(x->f)) rot((dir(x)^dir(x->f))?x:x->f); }
inline void access(node *x){
for(node *t=0;x;x=x->f){
splay(x);
x->isize-=t?t->size:0;
x->isize+=x->ch[1]?x->ch[1]->size:0;
x->ch[1]=t; t=x; Up(x);
}
}
inline void reverse(node *x){
access(x); splay(x); x->rev^=1;
}
inline int Size(int u){
node *x=a+u; reverse(x); return x->size;
}
inline void link(int u,int v){
node *x=a+u,*y=a+v;
reverse(y); reverse(x);
x->f=y; y->isize+=x->size;
access(x);
}
inline void cut(int u,int v){
node *x=a+u,*y=a+v;
reverse(x); access(y); splay(y); y->ch[0]=x->f=0; Up(y);
}
inline int linked(int u,int v){
node *x=a+u,*y=a+v;
reverse(x); access(y); splay(y);
while(y->ch[0]) y=y->ch[0];
return x==y;
}
};
namespace DG{
LCT fst[M+2];
set<int> iT[M+2][N],nT[M+2][N];
inline void link(int u,int v){
if(fst[0].linked(u,v)){
nT[0][u].insert(v); nT[0][v].insert(u);
}
else{
fst[0].link(u,v);
iT[0][u].insert(v); iT[0][v].insert(u);
}
}
void dfs(int lev,int u,int v,int fa,bool &f){
for(int i=lev+1;i<M;i++){
for(int t : iT[i][u])
if(t!=fa) dfs(lev,t,v,u,f);
}
set<int>::iterator i=iT[lev][u].begin();
while(i!=iT[lev][u].end() && !f){
int cur=*i;
iT[lev][u].erase(i++);
iT[lev][cur].erase(u);
fst[lev+1].link(u,cur);
iT[lev+1][u].insert(cur);
iT[lev+1][cur].insert(u);
dfs(lev,cur,v,u,f);
}
i=nT[lev][u].begin();
while(i!=nT[lev][u].end() && !f){
int cur=*i;
nT[lev][u].erase(i++);
nT[lev][cur].erase(u);
if(fst[lev].linked(cur,v)){
iT[lev][cur].insert(u);
iT[lev][u].insert(cur);
for(int j=0;j<=lev;j++)
fst[j].link(cur,u);//f=fst[j].linked(cur,u);
f=1;
}
else{
nT[lev+1][cur].insert(u);
nT[lev+1][u].insert(cur);
}
}
}
inline void fix(int lev,int u,int v){
bool f=0;
for(int i=lev;~i;i--){
if(fst[i].Size(u)>fst[i].Size(v)) swap(u,v);
dfs(i,u,v,0,f);
if(f) break;
}
}
inline void cut(int u,int v){
int lev;
for(lev=0;lev<M;lev++){
if(nT[lev][u].count(v)){
nT[lev][u].erase(v);
nT[lev][v].erase(u);
return ;
}
else if(iT[lev][u].count(v)){
iT[lev][u].erase(v);
iT[lev][v].erase(u);
break;
}
}
for(int i=0,c;i<=lev;i++)
fst[i].cut(u,v);//c=fst[i].linked(u,v);
fix(lev,u,v);
}
inline bool linked(int u,int v){
return fst[0].linked(u,v);
}
}
int n,m,lst;
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
read(n); read(m);
while(m--){
int opt,u,v; read(opt); read(u); read(v);
u^=lst; v^=lst;
if(opt==0)
DG::link(u,v);
else if(opt==1)
DG::cut(u,v);
else{
if(DG::linked(u,v)) lst=u;
else lst=v;
puts(lst==u?"Y":"N");
}
}
return 0;
}