BZOJ 2631 tree 动态树(Link-Cut-Tree)

时间:2022-12-28 22:02:42

题目大意:维护一种树形数据结构,支持以下操作:

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();
}