BZOJ 2001 Hnoi2010 城市建设 分治+LCT
2015-11-13 18:21
337 查看
题目大意:给定一张带权无向图,每次改变一条边的边权并询问最小生成树,不强制在线
日狗我为什么要写这个JB算法。。。
对时间进行分治,每条边的存在时间为一个区间,拆成log个;
带着LCT把分治结构DFS一遍,一个节点入栈时用上面的所有边扔进LCT动态维护最小生成树,出栈时还原所有操作
时间复杂度O(nlog2n)
如果没有特殊的卡常技巧请不要写这个算法
日狗我为什么要写这个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; }
相关文章推荐
- 对分治算法的几点思考
- BZOJ3275 Number (最小割)
- 关于“2”这个数字
- hdu 1007 -- Quoit Design
- [Leetcode题解]004 Median of Two Sorted Arrays
- 分治法求最大连续和
- poj2299 分治
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- [BZOJ2038][2009国家集训队][莫队][分块]小z的袜子
- [BZOJ2594][WC2006][LCT][MST]水管局长数据加强版
- [BZOJ2300][HAOI2011][动态凸包]防线修建
- [BZOJ1045][HAOI2008][贪心]糖果传递
- [BZOJ2539][CTSC2000][KM]丘比特的烦恼
- [BZOJ1004][HNOI2008][Burnside引理][DP]Cards
- [BZOJ1202][HNOI2005][并查集]狡猾的商人
- 分治的一次简单实践