BZOJ 2001 Hnoi2010 城市建設 分治+LCT
阿新 • • 發佈:2019-02-15
題目大意:給定一張帶權無向圖,每次改變一條邊的邊權並詢問最小生成樹,不強制線上
日狗我為什麼要寫這個JB演算法。。。
對時間進行分治,每條邊的存在時間為一個區間,拆成
帶著LCT把分治結構DFS一遍,一個節點入棧時用上面的所有邊扔進LCT動態維護最小生成樹,出棧時還原所有操作
時間複雜度
如果沒有特殊的卡常技巧請不要寫這個演算法
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;
namespace IStream{
const int _L=1<<15;
char buffer[_L],*S,*T;
inline char Get_Char()
{
if(S==T)
{
T=(S=buffer)+fread(buffer,1,_L,stdin);
if(S==T) return EOF;
}
return *S++;
}
inline int Get_Int()
{
char c;
int re=0;
for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
while(c>='0'&&c<='9')
re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
return re;
}
}
class OStream{
private:
static const int _L=1<<15;
char stack[30];int top;
char buffer[_L],*S;
public:
OStream()
{
S=buffer;
}
void Put_Long_Long(long long x)
{
stack[++top]='\n';
if(!x) stack[++top]='0';
else while(x)
stack[++top]=x%10+'0',x/=10;
while(top)
{
if(S==buffer+_L)
{
fwrite(buffer,1,_L,stdout);
S=buffer;
}
*S++=stack[top--];
}
}
~OStream()
{
*S=0;
fwrite(buffer,1,S-buffer,stdout);
}
}os;
int n,m,q;
int tim[M];
namespace Link_Cut_Tree{
struct abcd{
abcd *ls,*rs,*fa;
int x,y,z;
abcd *max_val;
bool rev_mark;
abcd() {}
abcd(int,int,int);
void Push_Up();
void Push_Down();
void Reverse();
}mempool[70700],*C=mempool,*tree[M],*edges[M],*null=new (C++)abcd(0,0,-1);
abcd :: abcd(int _,int __,int ___)
{
ls=rs=fa=null;
x=_;y=__;z=___;
max_val=this;
rev_mark=false;
}
void abcd :: Push_Up()
{
max_val=this;
if(ls->max_val->z > max_val->z)
max_val=ls->max_val;
if(rs->max_val->z > max_val->z)
max_val=rs->max_val;
}
void abcd :: Push_Down()
{
if(fa->ls==this || fa->rs==this)
fa->Push_Down();
if(rev_mark)
{
ls->Reverse();
rs->Reverse();
rev_mark=false;
}
}
void abcd :: Reverse()
{
swap(ls,rs);
rev_mark^=1;
}
void Zig(abcd *x)
{
abcd *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->rs=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Zag(abcd *x)
{
abcd *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->ls=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Splay(abcd *x)
{
x->Push_Down();
while(x->fa->ls==x || x->fa->rs==x)
{
abcd *y=x->fa,*z=y->fa;
if(x==y->ls)
{
if(y==z->ls)
Zig(y);
Zig(x);
}
else
{
if(y==z->rs)
Zag(y);
Zag(x);
}
}
x->Push_Up();
}
void Access(abcd *x)
{
abcd *y=null;
while(x!=null)
{
Splay(x);
x->rs=y;
x->Push_Up();
y=x;x=x->fa;
}
}
void Move_To_Root(abcd *x)
{
Access(x);
Splay(x);
x->Reverse();
}
bool Connected(abcd *x,abcd *y)
{
while(x->fa!=null)
x=x->fa;
while(y->fa!=null)
y=y->fa;
return x==y;
}
void Link(abcd *x,abcd *y)
{
Move_To_Root(x);
x->fa=y;
}
void Cut(abcd *x,abcd *y)
{
Move_To_Root(x);
Access(y);
Splay(y);
y->ls=null;
x->fa=null;
y->Push_Up();
}
}
struct List{
int num,val,next;
}table[100100*20];
int head[M<<2],tot;
void Insert(int p,int x,int y,int l,int r,int num,int val)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
table[++tot].num=num;
table[ tot].val=val;
table[ tot].next=head[p];
head[p]=tot;
return ;
}
if(r<=mid)
Insert(p<<1,x,mid,l,r,num,val);
else if(l>mid)
Insert(p<<1|1,mid+1,y,l,r,num,val);
else
Insert(p<<1,x,mid,l,mid,num,val) , Insert(p<<1|1,mid+1,y,mid+1,r,num,val) ;
}
pair<bool,Link_Cut_Tree::abcd*> operations[200200];int top; //0-刪除 1-插入
void Divide_And_Conquer(int p,int x,int y,long long ans)
{
using namespace Link_Cut_Tree;
int i,bottom=top,mid=x+y>>1;
for(i=head[p];i;i=table[i].next)
{
abcd *e=edges[table[i].num];
e->z=table[i].val;
if(e->x==e->y) continue;
if(Connected(tree[e->x],tree[e->y]))
{
Move_To_Root(tree[e->x]);
Access(tree[e->y]);
Splay(tree[e->x]);
abcd *temp=tree[e->x]->max_val;
if(temp->z <= e->z)
continue;
ans-=temp->z;
Cut(temp,tree[temp->x]);
Cut(temp,tree[temp->y]);
operations[++top]=make_pair(0,temp);
}
ans+=e->z;
Link(e,tree[e->x]);
Link(e,tree[e->y]);
operations[++top]=make_pair(1,e);
}
//a.clear();
if(x==y)
{
if(mid)
os.Put_Long_Long(ans);
}
else
Divide_And_Conquer(p<<1,x,mid,ans),Divide_And_Conquer(p<<1|1,mid+1,y,ans);
while(top>bottom)
{
pair<bool,abcd*> temp=operations[top--];
if(temp.first==0)
{
Link(temp.second,tree[temp.second->x]);
Link(temp.second,tree[temp.second->y]);
}
else
{
Cut(temp.second,tree[temp.second->x]);
Cut(temp.second,tree[temp.second->y]);
}
}
}
int main()
{
#ifdef PoPoQQQ
freopen("2001.in","r",stdin);
freopen("2001.out","w",stdout);
#endif
using namespace Link_Cut_Tree;
int i,x,y,z;
cin>>n>>m>>q;
for(i=1;i<=n;i++)
tree[i]=new (C++)abcd(0,0,-1);
for(i=1;i<=m;i++)
{
x=IStream::Get_Int();
y=IStream::Get_Int();
z=IStream::Get_Int();
edges[i]=new (C++)abcd(x,y,z);
tim[i]=0;
}
for(i=1;i<=q;i++)
{
x=IStream::Get_Int();
y=IStream::Get_Int();
Insert(1,0,q,tim[x],i-1,x,edges[x]->z);
tim[x]=i;edges[x]->z=y;
}
for(i=1;i<=m;i++)
Insert(1,0,q,tim[i],q,i,edges[i]->z);
Divide_And_Conquer(1,0,q,0);
return 0;
}