LG P1501 [国家集训队]Tree II(LCT,多重标记)

124 篇文章 0 订阅
26 篇文章 1 订阅

题目
我数据结构果然还是太菜了。
有多重标记的时候可以定义群(其实就是满足结合律结构体)来简化代码。
( a , b ) (a,b) (a,b)可以使 ( v a l [ x ] , s u m [ x ] ) (val[x],sum[x]) (val[x],sum[x])变为 ( v a l [ x ] ∗ a + b , s u m [ x ] ∗ a + b ∗ s i z [ x ] ) (val[x]*a+b,sum[x]*a+b*siz[x]) (val[x]a+b,sum[x]a+bsiz[x])
那么可以知道 ( a , b ) ∗ ( c , d ) = ( a c , b c + d ) (a,b)*(c,d)=(ac,bc+d) (a,b)(c,d)=(ac,bc+d)
重载运算符,美滋滋。
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
#define mod 51061
using namespace std;

int n,q;

struct tag{
	LL m,a;
	tag(LL m=1,LL a=0):m(m),a(a){}
	tag operator *(const tag &B)const{ return tag(1ll*m*B.m%mod,(1ll*a*B.m%mod+B.a)%mod); }  
}lazy[maxn];

namespace LCT{
	int fa[maxn],rev[maxn],ch[maxn][2],siz[maxn];
	LL sum[maxn],val[maxn];
	#define il inline 
	#define pa fa[x]
	il int inr(int x){ return ch[pa][1]==x; }
	il int isr(int x){ return ch[pa][0]!=x&&ch[pa][1]!=x; }
	il void dtp(int x,tag v){
		val[x] = (val[x] * v.m + v.a) % mod;
		sum[x] = (sum[x] * v.m + v.a * siz[x]) % mod;
		lazy[x] = lazy[x] * v;
	}
	il void dt(int x){ 
		if(rev[x]){
			swap(ch[x][0],ch[x][1]),rev[x]=0;
			if(ch[x][0]) rev[ch[x][0]] ^= 1;
			if(ch[x][1]) rev[ch[x][1]] ^= 1;
		}
		if(lazy[x].a!=0 || lazy[x].m!=1){
			if(ch[x][0]) dtp(ch[x][0],lazy[x]);
			if(ch[x][1]) dtp(ch[x][1],lazy[x]);
			lazy[x] = tag(1,0);
		}
	}
	il void dtpath(int x){ if(!isr(x)) dtpath(pa);dt(x); }
	il void upd(int x){
		sum[x] = (sum[ch[x][0]] + sum[ch[x][1]] + val[x]) % mod;
		siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
	}
	il void rot(int x){
		int y=fa[x],z=fa[y],c=inr(x);
		if(!isr(y)) ch[z][inr(y)]=x; 
		(ch[y][c]=ch[x][!c])&&(fa[ch[y][c]]=y);
		fa[fa[ch[x][!c]=y]=x]=z;
		upd(y),upd(x);
	}
	il void splay(int x){
		dtpath(x);
		for(;!isr(x);rot(x)){
			if(!isr(pa)) rot(inr(x)==inr(pa)?pa:x);
			}
	}
	il int access(int x,int y=0){
		for(;x;x=fa[y=x]) splay(x),ch[x][1]=y,upd(x);
		return y;
	}
	il void bert(int x){
		access(x),splay(x),rev[x]^=1;
	}
	il int sert(int x){
		access(x),splay(x);
		for(;ch[x][0];)x=ch[x][0];
		return x;
	}
	il void link(int x,int y){
		bert(x);
		if(sert(y)==x) return;
		fa[x]=y;
	}
	il void cut(int x,int y){
		bert(x),access(y),splay(y);
		if(sert(y)!=x || siz[y]!=2) return;
		fa[x]=ch[y][0]=0;
	}
	il int split(int x,int y){
		bert(x),access(y),splay(y);
		return y;
	}
	il void modify(int x,int y,tag c){
		dtp(split(x,y),c);
	}
	il LL query(int x,int y){
		return sum[split(x,y)];
	}
}

int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) LCT::modify(i,i,tag(1,1)),LCT::siz[i]=1;
	for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),LCT::link(u,v);
	char s[2];
	for(int u,v,u1,v1;q--;){
		scanf("%s",s);
		if(s[0] == '+' || s[0]=='*'){
			scanf("%d%d%d",&u,&v,&u1);
			if(s[0] == '*') LCT::modify(u,v,tag(u1,0));
			else LCT::modify(u,v,tag(1,u1));
		}
		else if(s[0]=='-'){
			scanf("%d%d%d%d",&u,&v,&u1,&v1);
			LCT::cut(u,v);
			LCT::link(u1,v1);
		}
		else{
			scanf("%d%d",&u,&v);
			printf("%lld\n",LCT::query(u,v));
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值