BZOJ 2631(tree-LCT链上修改)

2631: tree

Time Limit: 30 Sec   Memory Limit: 128 MB
Submit: 2513   Solved: 846
[ Submit][ Status][ Discuss]

Description

 一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c:将u到v的路径上的点的权值都加上自然数c;
- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
* u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

Input

  第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作

Output

  对于每个/对应的答案输出一行

Sample Input

3 2
1 2
2 3
* 1 3 4
/ 1 1

Sample Output

4


HINT

数据规模和约定

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4


Source




LCT,区间加,区间乘

其实pushdown操作只需要splay的时候传下来,确保splay(x)后,x更新为正确的就行了,

其他的地方权当懒得删了



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (51061)
#define MAXN (100000+10)
#define MAXQ (100000+10)
#define MAXC (10000) 
typedef unsigned int ll;
void mul(ll &a,ll b){a=(a*b)%F;}
void add(ll &a,ll b){a=(a%F+b%F)%F;}


class LCT
{
public:
	int father[MAXN],siz[MAXN];
	int ch[MAXN][2];
	bool root[MAXN];
	bool rev[MAXN];
	ll addv[MAXN],mulv[MAXN],sumv[MAXN],val[MAXN];
	void mem(int n)
	{
		MEM(father) MEM(siz) MEM(root)
		For(i,n+1) siz[i]=root[i]=mulv[i]=val[i]=sumv[i]=1;    root[0]=1;
		MEM(ch)  MEM(rev)
		MEM(addv)
	}
	void pushdown(int x)
	{
		if (!x) return ; 
		if (rev[x]) {
			if (ch[x][0]) rev[ch[x][0]]^=1;
			if (ch[x][1]) rev[ch[x][1]]^=1;
			swap(ch[x][0],ch[x][1]);
			rev[x]^=1;
		} 
		if (mulv[x]!=1) {
			if (ch[x][0]) mul(mulv[ch[x][0]],mulv[x]),mul(addv[ch[x][0]],mulv[x]),mul(val[ch[x][0]],mulv[x]),mul(sumv[ch[x][0]],mulv[x]);
			if (ch[x][1]) mul(mulv[ch[x][1]],mulv[x]),mul(addv[ch[x][1]],mulv[x]),mul(val[ch[x][1]],mulv[x]),mul(sumv[ch[x][1]],mulv[x]);
			mulv[x]=1;
		}
		if (addv[x]) {
			if (ch[x][0]) add(addv[ch[x][0]],addv[x]),add(val[ch[x][0]],addv[x]),add(sumv[ch[x][0]],addv[x]*siz[ch[x][0]]);
			if (ch[x][1]) add(addv[ch[x][1]],addv[x]),add(val[ch[x][1]],addv[x]),add(sumv[ch[x][1]],addv[x]*siz[ch[x][1]]);
			addv[x]=0;
		}
	}
	void maintain(int x)
	{
		siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
		sumv[x]=(sumv[ch[x][0]]+sumv[ch[x][1]]+val[x])%F; 
	}
	void rotate(int x)
	{
		int y=father[x],kind=ch[y][1]==x;
		
		ch[y][kind]=ch[x][!kind];
		if (ch[y][kind]) {
			father[ch[y][kind]]=y;
		}
		father[x]=father[y];
		father[y]=x;
		ch[x][!kind]=y;
		if (root[y])
		{
			root[x]=1;root[y]=0;
		}
		else
		{
			ch[father[x]][ ch[father[x]][1]==y ] = x;
		}
		maintain(y);maintain(x);
	}
	
	void P(int x)
	{
		if (!root[x]) P(father[x]);
		pushdown(x);
	}
	
	void splay(int x)
	{
		P(x);
		while(!root[x])
		{
			int y=father[x];
			int z=father[y];
			if (root[y]) rotate(x);
			else if ( (ch[y][1]==x)^(ch[z][1]==y) )
			{
				rotate(x); rotate(x);
			} 
			else 
			{
				rotate(y); rotate(x);
			}
		} 
	}
	
	
	
	int access(int x)
	{
		int y=0;
		do
		{
			splay(x);
			if (ch[x][1]) root[ch[x][1]]=1;
			ch[x][1]=y;
			if (y) root[y]=0;		
			maintain(x);
			y = x;
			x=father [x]; 
		} while (x) ;
		return y;
	}
	
	void cut(int x)
	{
		access(x);
		splay(x);
		
		father[ch[x][0]]=0;
		root[ch[x][0]]=1;
		ch[x][0]=0;
		maintain(x);
	}
	
	void join(int x,int y)
	{
		make_root(x);
		access(y);
		splay(y);
		ch[y][1]=x;
		father[x]=y;
		maintain(y);
		root[x]=0;
	}
	void reverse(int x){
		rev[x]^=1;	 // 标记记完后迅速处理 
	}
	void make_root(int x){
		access(x);splay(x);
		reverse(x);pushdown(x);
	}
	int get_root(int x){
		access(x);
		splay(x);
		do {
			pushdown(x);
			if (ch[x][0]) x=ch[x][0];
			else break;
		}while(1);
		return x;
	}
	
	void Mul(int x,ll cost){
		pushdown(x);mulv[x]=cost; 
		mulv[x]=cost;mul(val[x],cost);mul(addv[x],cost);mul(sumv[x],cost); 
	}
	void Add(int x,ll cost){
		pushdown(x);
		addv[x]=cost;add(val[x],cost);add(sumv[x],cost*siz[x]); 
	}
	
	
	
}S;

int n,q;

int main()
{
//	freopen("bzoj2631.in","r",stdin);
//	freopen(".out","w",stdout);
		 
	scanf("%d%d",&n,&q);
	S.mem(n);
	For(i,n-1) {
		int u,v;
		scanf("%d%d",&u,&v);
		S.join(u,v);
	}
	
	For(i,q) {
		char c[2];
		int u,v;
		scanf("%s%d%d",c,&u,&v);
		if (c[0]=='+'||c[0]=='*') {
			int cost;
			scanf("%d",&cost);
			S.make_root(u);
			S.access(v);
			S.splay(v);
			if ('+'==c[0]) S.Add(v,cost);
			else S.Mul(v,cost); 
			
		} else if (c[0]=='-') {
			int u2,v2;
			scanf("%d%d",&u2,&v2);
			S.make_root(u);
			S.cut(v);
			S.join(u2,v2);
			
		} else if (c[0]=='/') {
			S.make_root(u);
			S.access(v);
			S.splay(v);
			printf("%u\n",S.sumv[v]%F);	
		}
	}
	
	
	
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值