标签:bzoj bzoj2631 link-cut-tree 动态树 lct
题目大意:维护一种树形数据结构,支持以下操作:
1.树上两点之间的点权值+k。
2.删除一条边,增加一条边,保证加边之后还是一棵树。
3.树上两点之间点权值*k。
4.询问树上两点时间点的权值和。
思路:利用动态树维护这棵树,lct的裸题。如果不会下传标记的,先去做BZOJ1798,也是这样的标记,只不过在线段树上做,比这个要简单许多。
这个也是我的LCT的第一题,理解起来十分困难啊。。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define MO 51061 using namespace std; struct Complex{ int size; unsigned int val,sum; Complex *son[2],*father; bool reverse; int m_mark,p_mark; bool Check() { return father->son[1] == this; } void Reverse(); void Plus(unsigned int c); void Mulitiply(unsigned int c); void PushUp(); void PushDown(); }*tree[MAX],*nil = new Complex(); int cnt,points,asks; int head[MAX],total; int next[MAX << 1],aim[MAX << 1]; char c[10]; void Pretreatment(); inline Complex *NewComplex(unsigned int val); inline void Add(int x,int y); void DFS(int x,int last); inline void Splay(Complex *a); inline void Rotate(Complex *a,bool dir); inline void PushPath(Complex *a); inline void Access(Complex *a); inline void ToRoot(Complex *a); inline void Link(Complex *x,Complex *y); inline void Cut(Complex *x,Complex *y); int main() { Pretreatment(); cin >> points >> asks; for(int x,y,i = 1;i < points; ++i) { scanf("%d%d",&x,&y); Add(x,y),Add(y,x); } for(int i = 1;i <= points; ++i) tree[i] = NewComplex(1); DFS(1,-1); for(int x,y,z,i = 1;i <= asks; ++i) { scanf("%s%d%d",c,&x,&y); if(c[0] == '+') { scanf("%d",&z); ToRoot(tree[x]); Access(tree[y]); Splay(tree[y]); tree[y]->Plus(z); } else if(c[0] == '-') { Cut(tree[x],tree[y]); scanf("%d%d",&x,&y); Link(tree[x],tree[y]); } else if(c[0] == '*') { scanf("%d",&z); ToRoot(tree[x]); Access(tree[y]); Splay(tree[y]); tree[y]->Mulitiply(z); } else { ToRoot(tree[x]); Access(tree[y]); Splay(tree[y]); printf("%d\n",tree[y]->sum); } } return 0; } void Complex:: PushUp() { sum = (son[0]->sum + son[1]->sum + val) % MO; size = son[0]->size + son[1]->size + 1; } void Complex:: PushDown() { if(m_mark != 1) { son[0]->Mulitiply(m_mark); son[1]->Mulitiply(m_mark); m_mark = 1; } if(p_mark) { son[0]->Plus(p_mark); son[1]->Plus(p_mark); p_mark = 0; } if(reverse) { son[0]->Reverse(); son[1]->Reverse(); reverse = false; } } void Complex:: Reverse() { reverse ^= 1; swap(son[0],son[1]); } void Complex:: Plus(unsigned int c) { if(this == nil) return ; val = (val + c) % MO; p_mark = (p_mark + c) % MO; sum = (sum + (size * c) % MO) % MO; } void Complex:: Mulitiply(unsigned int c) { if(this == nil) return ; m_mark = (m_mark * c) % MO; val = (val * c) % MO; p_mark = (p_mark * c) % MO; sum = (sum * c) % MO; } inline void Add(int x,int y) { next[++total] = head[x]; aim[total] = y; head[x] = total; } void Pretreatment() { nil->size = 0; nil->son[0] = nil->son[1] = nil->father = nil; } inline Complex *NewComplex(unsigned int val) { Complex *re = new Complex(); re->val = re->sum = val; re->reverse = false; re->son[0] = re->son[1] = re->father = nil; re->p_mark = 0; re->m_mark = 1; re->size = 1; return re; } void DFS(int x,int last) { for(int i = head[x];i;i = next[i]) { if(aim[i] == last) continue; tree[aim[i]]->father = tree[x]; DFS(aim[i],x); } } inline void Splay(Complex *a) { PushPath(a); while(a == a->father->son[0] || a == a->father->son[1]) { Complex *p = a->father->father; if(p->son[0] != a->father && p->son[1] != a->father) Rotate(a,!a->Check()); else if(!a->father->Check()) { if(!a->Check()) Rotate(a->father,true),Rotate(a,true); else Rotate(a,false),Rotate(a,true); } else { if(a->Check()) Rotate(a->father,false),Rotate(a,false); else Rotate(a,true),Rotate(a,false); } } a->PushUp(); } inline void Rotate(Complex *a,bool dir) { Complex *f = a->father; f->son[!dir] = a->son[dir]; f->son[!dir]->father = f; a->son[dir] = f; a->father = f->father; if(f->father->son[0] == f || f->father->son[1] == f) f->father->son[f->Check()] = a; f->father = a; f->PushUp(); } inline void PushPath(Complex *a) { static Complex *stack[MAX]; int top = 0; for(;a->father->son[0] == a || a->father->son[1] == a;a = a->father) stack[++top] = a; stack[++top] = a; while(top) stack[top--]->PushDown(); } inline void Access(Complex *a) { Complex *last = nil; while(a != nil) { Splay(a); a->son[1] = last; a->PushUp(); last = a; a = a->father; } } inline void ToRoot(Complex *a) { Access(a); Splay(a); a->Reverse(); } inline void Link(Complex *x,Complex *y) { ToRoot(x); x->father = y; } inline void Cut(Complex *x,Complex *y) { ToRoot(x); Access(y); Splay(y); y->son[0]->father = nil; y->son[0] = nil; y->PushUp(); }
BZOJ 2631 tree 动态树(Link-Cut-Tree)
标签:bzoj bzoj2631 link-cut-tree 动态树 lct
原文地址:http://blog.csdn.net/jiangyuze831/article/details/39640223