BZOJ 2631: tree LCT

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 4855  Solved: 1659
[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


LCT练手题


pushdown写错调一上午。

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef unsigned int uint;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=100100,mod=51061;

int ch[N][2],size[N],fa[N];
uint V[N],sum[N],add[N],mul[N];
bool rev[N];

inline void pushup(int k)
{
	int ls=ch[k][0],rs=ch[k][1];
	size[k]=size[ls]+size[rs]+1;
	sum[k]=(sum[ls]+sum[rs]+V[k])%mod;
}

inline void pushdown(int k)
{
	int ls=ch[k][0],rs=ch[k][1];
	if(mul[k]!=1)
	{
		(V[ls]*=mul[k])%=mod;
		(V[rs]*=mul[k])%=mod;
		(mul[ls]*=mul[k])%=mod;
		(mul[rs]*=mul[k])%=mod;
		(add[ls]*=mul[k])%=mod;
		(add[rs]*=mul[k])%=mod;
		(sum[ls]*=mul[k])%=mod;
		(sum[rs]*=mul[k])%=mod;
		mul[k]=1;
	}
	if(add[k])
	{
		sum[ls]=(sum[ls]+add[k]*size[ls])%mod;
		sum[rs]=(sum[rs]+add[k]*size[rs])%mod;
		(add[ls]+=add[k])%=mod;
		(add[rs]+=add[k])%=mod;
		(V[ls]+=add[k])%=mod;
		(V[rs]+=add[k])%=mod;
		add[k]=0;
	}
	if(rev[k])
	{
		rev[k]=0;
		rev[ls]^=1;rev[rs]^=1;
		swap(ch[k][0],ch[k][1]);
	}
}

inline bool isroot(int k)
{return ch[fa[k]][0]!=k&&ch[fa[k]][1]!=k;}

void getdown(int k)
{
	if(!isroot(k)) getdown(fa[k]);
	pushdown(k);
}

inline void rotate(int x)
{
	int y=fa[x],z=fa[y],l,r;
	l=(ch[y][1]==x);r=l^1;
	if(!isroot(y)) ch[z][ch[z][1]==y]=x;
	fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
	ch[y][l]=ch[x][r];ch[x][r]=y;
	pushup(y);pushup(x);
}

void splay(int x)
{
	getdown(x);
	int y,z;
	while(!isroot(x))
	{
		y=fa[x];z=fa[y];
		if(!isroot(y))
		{
			if((ch[y][0]==x)^(ch[z][0]==y))rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}

void access(int x)
{int t=0;while(x){splay(x);ch[x][1]=t;pushup(x);t=x;x=fa[x];}}

void rever(int x)
{access(x);splay(x);rev[x]^=1;}

void split(int u,int v)
{rever(u);access(v);splay(v);}

void link(int u,int v)
{rever(u);fa[u]=v;splay(u);}

void cut(int u,int v)
{split(u,v);ch[v][0]=fa[u]=0;}

void modify_add(int u,int v,int val)
{
	split(v,u);
	sum[u]=(sum[u]+size[u]*val)%mod;
	(add[u]+=val)%=mod;
	(V[u]+=val)%=mod;
}

void modify_mul(int u,int v,int val)
{
	split(v,u);
	(sum[u]*=val)%=mod;
	(mul[u]*=val)%=mod;
	(add[u]*=val)%=mod;
	(V[u]*=val)%=mod;
}

void query(int u,int v)
{
	split(v,u);
	print(sum[u]);puts("");
}

int main()
{
	register int n=read(),Q=read();
	register int u,v,x,y;
	for(u=1;u<=n;++u)
		mul[u]=V[u]=sum[u]=size[u]=1;
	for(x=1;x<n;++x)
	{
		u=read();v=read();
		link(u,v);
	}
	char opt[2];
	while(Q--)
	{
		scanf("%s",opt);
		u=read();v=read();
		switch(opt[0])
		{
			case '+':
				x=read();
				modify_add(u,v,x);
				break;
			case '-':
				x=read();y=read();
				cut(u,v);link(x,y);
				break;
			case '*':
				x=read();
				modify_mul(u,v,x);
				break;
			case '/':
				query(u,v);
				break;
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值