1. 程式人生 > >BZOJ 2001 Hnoi2010 城市建設 分治+LCT

BZOJ 2001 Hnoi2010 城市建設 分治+LCT

題目大意:給定一張帶權無向圖,每次改變一條邊的邊權並詢問最小生成樹,不強制線上

日狗我為什麼要寫這個JB演算法。。。

對時間進行分治,每條邊的存在時間為一個區間,拆成log個;
帶著LCT把分治結構DFS一遍,一個節點入棧時用上面的所有邊扔進LCT動態維護最小生成樹,出棧時還原所有操作

時間複雜度O(nlog2n)

如果沒有特殊的卡常技巧請不要寫這個演算法

#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; }