UPD:已被HACK
学一发黑科技
给边设一个权值,对每一种权值 i i i 维护权值大于等于 i i i 的边构成的最大生成树 T i T_i Ti
加边
一个边刚被加入时的权值设为0,如果它连接两个联通块,就把它设为树边,否则设为非树边
删边
假设要删除边 ( x , y ) (x,y) (x,y),设它的权值为 w w w
如果它是一条非树边,直接删去,否则要找一条边替代它。
显然替代它的边的边权小于等于 w w w
设删掉这条边后形成的两个联通块为 X X X 和 Y Y Y,不妨设 ∣ X ∣ ≤ ∣ Y ∣ |X|\le |Y| ∣X∣≤∣Y∣
那么就是要找一条边权小于等于 w w w 且连接 X X X 和 Y Y Y 的边
暴力枚举所有和 X X X 相连的边就可以了…如果当前枚举到边是 X X X 内部的,把它权值加一,否则结束查找
用LCT维护复杂都是 O ( m log 2 n ) O(m\log^2 n) O(mlog2n) 的
复杂度证明的话
因为每次最多把一个联通块的一半权值加一,而 T i + 1 ⊆ T i T_{i+1}\subseteq T_i Ti+1⊆Ti,所以 T i + 1 T_{i+1} Ti+1 的大小最大为 T i T_{i} Ti 的一半,那么层数就是 log n \log n logn 的
#include
#include
#include
#include
#include
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 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::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