树链剖分+提升题

十七波 Q Falsita、P[Ynoi2017]由乃的OJ

description:

她们所在的精神世界是一棵以 1 号节点为根的树,每个树上的节点 u 都有一个权值Wu,她们每个人分别都在一个节点上,达成共识的方法就是两个人都到达一个共识节点(即到达它们的最近公共祖先)。
一个点 u 与另外一个点 v 之间想要达到共识需要花费的代价为Wu+Wv。
有时两人的精神有所触动时,有时点的权值会改变成某个数,有时以某个点的子树中的所有点的权值会加上某个数。
Falsita 和 Fine 经常需要达成共识,每一次询问,已知达成的共识节点,求她们花费的期望代价。

  1. S u delta 表示将节点 u 的权值加上 delta 。
  2. M u delta 表示将以节点 u 为根的子树中的所有节点的权值加上 delta。
  3. Q u 表示询问共识节点为 u 时的答案。

solution:
求值

我们将修改分为两种情况,考虑把修改产生的影响分为向上,和向下的

  1. 对于一个节点的修改,会对根节点,到这个点的路径上的点都产生贡献;
  2. 如果只改变节点本身,对下面的子树不会有影响,

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5+10;
ll n,m,w[N];
ll en[N],nex[N],lst[N],tot;
void add(ll x,ll y){en[++tot]=y;nex[tot]=lst[x];lst[x]=tot;}
ll dep[N],f[N],sz[N],sum[N];
ll chu[N],zi[N];
ll top[N],son[N],bl[N],nid[N],id,ou[N];
void dfs(ll u,ll fa){
	sum[u] = w[u];sz[u] = 1;
	f[u] = fa;ll Msz = 0;
	for(ll i=lst[u];i;i=nex[i])
	{
		ll v = en[i];
		if(v==fa)continue;
		dep[v] = dep[u]+1;dfs(v,u);
		sz[u]+=sz[v];chu[u]-=sz[v]*sz[v];
		sum[u]+=sum[v];zi[u]-=sz[v]*sum[v];
		if(sz[v]>Msz){
			son[u] = v;
			Msz = sz[v];
		}
	}
	chu[u]+=sz[u]*sz[u]-1;
	zi[u]+=sz[u]*sum[u]-w[u];
}
void ddfs(ll u,ll anc){
	nid[u] = ++id;bl[id] = u;top[u] = anc;
	if(son[u])ddfs(son[u],anc);
	for(ll i=lst[u];i;i=nex[i])
	{
		ll v = en[i];
		if(v==f[u]||v == son[u])continue;
		ddfs(v,v);
	}
	ou[u]=id;
}
ll lzy1[N<<3],lzy2[N<<3],seg[N<<3];
void build(ll p,ll l,ll r){
	if(l==r)
	{
		seg[p] = zi[bl[l]];
//		printf("%lld %lld\n",l,seg[p]);
		return;
	}
	ll mid = (l + r) >> 1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
}
void pushdown(ll p){
	lzy1[p<<1]+=lzy1[p];lzy1[p<<1|1]+=lzy1[p];
	lzy2[p<<1]+=lzy2[p];lzy2[p<<1|1]+=lzy2[p];
	lzy2[p]=lzy1[p] = 0;
}
//´øson 
void modify1(ll p,ll l,ll r,ll x,ll y,ll z){
	if(x>y)return;
	if(l>=x&&r<=y)
	{
		lzy1[p]+=z;return;
	}
	if(l==r)return;
	if(lzy1[p])pushdown(p);
	ll mid = (l + r) >> 1;
	if(x<=mid)modify1(p<<1,l,mid,x,y,z);
	if(y>mid)modify1(p<<1|1,mid+1,r,x,y,z);
	return;
}
//ÐÞ¸Ä×ÓÊ÷ 
void modify3(ll p,ll l,ll r,ll x,ll y,ll z){
	if(x>y)return;
	if(l>=x&&r<=y)
	{
		lzy2[p]+=z;return;
	}
	if(l==r)return;
	if(lzy2[p])pushdown(p);
	ll mid = (l + r) >> 1;
	if(x<=mid)modify3(p<<1,l,mid,x,y,z);
	if(y>mid)modify3(p<<1|1,mid+1,r,x,y,z);
	return;
}
//ÐÞ¸ÄÖØÁ´Á´½Ó´¦(µ¥µãÐ޸ģ© 
void modify2(ll p,ll l,ll r,ll x,ll v,ll z){
	if(l==r)
	{
		seg[p]+=z*(sz[bl[x]]-sz[v]);return;
	}
	ll mid = (l + r) >> 1;
	if(x<=mid)modify2(p<<1,l,mid,x,v,z);
	else modify2(p<<1|1,mid+1,r,x,v,z);
}
double query(ll p,ll l,ll r,ll x){
	if(l==r)
	{
		ll tmp = bl[x];
//		printf("%lld %lld\n",seg[p],lzy1[p]);
		return 2.00*(lzy1[p]*(sz[tmp]-sz[son[tmp]])+seg[p])/(1.00*chu[bl[l]])+2.00*lzy2[p];
	}
	if(lzy1[p]||lzy2[p])pushdown(p);
	ll mid = (l + r) >> 1;
	if(x<=mid)return query(p<<1,l,mid,x);
	else return query(p<<1|1,mid+1,r,x);
}
void change(ll u,ll x){
	while(top[u]!=top[1])
	{
		modify1(1,1,n,nid[top[u]],nid[u]-1,x);
		modify2(1,1,n,nid[f[top[u]]],top[u],x);
		u = f[top[u]];
	}
	modify1(1,1,n,nid[1],nid[u]-1,x);
}
int main(){	
	scanf("%lld%lld",&n,&m);
	for(ll i=2,x;i<=n;i++){scanf("%lld",&x);add(x,i);}
	for(ll i=1;i<=n;i++)scanf("%lld",w+i);
	dfs(1,0);ddfs(1,1);
	build(1,1,n);
	sz[n+1]=1;
	for(ll i=1,u,v;i<=m;i++)
	{
		char otp[2];
		scanf("%s",otp);
		if(otp[0]=='S')
		{
			scanf("%lld%lld",&u,&v);
			change(u,v);modify2(1,1,n,nid[u],n+1,v);
		}
		if(otp[0]=='M')	
		{
			scanf("%lld%lld",&u,&v);
			change(u,sz[u]*v);
			modify3(1,1,n,nid[u],ou[u],v);
		}
		if(otp[0]=='Q')
		{
			scanf("%lld",&u);
			printf("%.6lf\n",query(1,1,n,nid[u]));
		}
	}
}

由乃的oj

**solution:**我们用wl[p][0/1];wr[p][0/1]来表示在p的区间内从左边/从右边全部以1/0输入最后得到的结果
update更新的时候我们就看根据(0/1)的情况保留需要的位数;

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+10;
const unsigned long long Top = 18446744073709551615ULL;
int n,m,K;
int en[N],nex[N],lst[N],tot;
void add(int x,int y){en[++tot]=y;nex[tot]=lst[x];lst[x]=tot;}
int f[N],dep[N],sz[N];
int son[N],top[N],nid[N],id;
void dfs(int u,int fa){
	f[u] = fa;sz[u] = 1;int Msz = 0;
	for(int i=lst[u];i;i=nex[i])
	{
		int v = en[i];
		if(v==fa)continue;
		dep[v] = dep[u] + 1;
		dfs(v,u);
		sz[u]+=sz[v];
		if(sz[v]>Msz){
			son[u] = v;Msz = sz[v];
		}
	}
	return;
}
void ddfs(int u,int anc){
	top[u] = anc;nid[u] = ++id;
	if(son[u])ddfs(son[u],anc);
	for(int i=lst[u];i;i=nex[i])
	{
		int v = en[i];
		if(v==f[u]||v==son[u])continue;
		ddfs(v,v);
	}
}

unsigned long long wl[N<<3][2],wr[N<<3][2];
//L´Ó×óÈ룬R´ÓÓÒÈë 
void update(int p){
	unsigned long long el1,el0,er1,er0;
	int ls = p<<1,rs = p<<1|1;
	el1 = wl[ls][1];el0 = wl[ls][0]; 
	er1 = wr[rs][1];er0 = wr[rs][0];
	
	wl[p][1] = (wl[rs][1]&el1)+(wl[rs][0]&(~el1));
	wl[p][0] = (wl[rs][1]&el0)+(wl[rs][0]&(~el0));
	wr[p][1] = (wr[ls][1]&er1)+(wr[ls][0]&(~er1));
	wr[p][0] = (wr[ls][1]&er0)+(wr[ls][0]&(~er0));
	return;
}
void modify(int p,int l,int r,int x,unsigned long long w,int otp){
	if(l==r)
	{
		if(otp==1)
		{
			wr[p][0] = wl[p][0] = 0;
			wr[p][1] = wl[p][1] = w;
		}
		if(otp==2)
		{
			wr[p][0] = wl[p][0] = w;
			wr[p][1] = wl[p][1] = Top;
		}
		if(otp==3)
		{
			wr[p][0] = wl[p][0] = w;
			wr[p][1] = wl[p][1] = Top^w;
		}
		return;
	}
	int mid  = (l + r) >> 1;
	if(x<=mid)modify(p<<1,l,mid,x,w,otp);
	else modify(p<<1|1,mid+1,r,x,w,otp);
	update(p);
}
struct node{
	unsigned long long num0,num1;
}ans2[1000];
node query(int p,int l,int r,int x,int y,int dir){
	if(l>=x&&r<=y)
	{
		if(dir)return (node){wl[p][0],wl[p][1]};
		else return (node){wr[p][0],wr[p][1]};
	}
	if(l == r)return(node){0,0};
	int mid = (l + r) >> 1;
	node tmp1,tmp2,tmp3;     
	if(x<=mid){
		tmp1 = query(p<<1,l,mid,x,y,dir);
		if(y<=mid)return tmp1;
	}
	if(y>mid){
		tmp2 = query(p<<1|1,mid+1,r,x,y,dir);
		if(x>mid)return tmp2;
	}                             
	if(dir)
	{
		tmp3.num0 = (tmp1.num0&tmp2.num1)+((~tmp1.num0)&tmp2.num0);
		tmp3.num1 = (tmp1.num1&tmp2.num1)+((~tmp1.num1)&tmp2.num0);
	}
	else {
		tmp3.num0 = (tmp2.num0&tmp1.num1)+((~tmp2.num0)&tmp1.num0);
		tmp3.num1 = (tmp2.num1&tmp1.num1)+((~tmp2.num1)&tmp1.num0);
	}
	return tmp3;
}
unsigned long long gets(int u,int v,unsigned long long  z){
	 int cnt2 = 0,flag = 0,l = 1,r = 0,mark1=0,mark0=0;
	 unsigned long long res1=0,res0=0,ans=0;
	 while(top[u]!=top[v])
	 {
	 	if(dep[top[u]]<dep[top[v]]){
	 		ans2[++cnt2] = query(1,1,n,nid[top[v]],nid[v],l);
			 v =f[top[v]];
		}                                                                                                               
	 	else {
		 	node tmp = query(1,1,n,nid[top[u]],nid[u],r);
		 	if(!mark1)res1 = tmp.num1,mark1=1;
		 	else res1 = (res1&tmp.num1)+((~res1)&tmp.num0);
		 	if(!mark0)res0 = tmp.num0,mark0=1;
		 	else res0 = (res0&tmp.num1)+((~res0)&tmp.num0);
		 	u = f[top[u]];
		}
	 }
	 if(dep[u]>dep[v])ans2[++cnt2] = query(1,1,n,nid[v],nid[u],r);
	 else ans2[++cnt2] = query(1,1,n,nid[u],nid[v],l);
	 for(int i=cnt2;i>=1;i--)
	 {
	 	if(!mark1)res1 = ans2[i].num1,mark1 = 1;
	 	else res1 = (res1&ans2[i].num1)+((~res1)&ans2[i].num0);
		if(!mark0)res0 = ans2[i].num0,mark0 = 1;
		else res0 = (res0&ans2[i].num1)+((~res0)&ans2[i].num0);
	 }
	 for(int i=63;i>=0;i--)
	 {
	 	if(((res0>>i)&1)||( !flag&&!((z>>i)&1) ) || !((res1>>i)&1) )
	 	{
	 		unsigned long long tt = (res0>>i)&1;
	 		ans |= tt<<i;if((z>>i)&1)flag=1;
	 		continue;
		}
	 	if( flag||((z>>i)&1) )
	 	{
	 		unsigned long long tt = (res1>>i)&1;
	 		ans |= tt<<i;
		}
	 }
	 return ans;
}
int otp[N];
unsigned long long a[N];
int main(){
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1;i<=n;i++)scanf("%d%llu",otp+i,a+i);
	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(y,x),add(x,y);
	dfs(1,0);ddfs(1,1);
	for(int i=1;i<=n;i++)modify(1,1,n,nid[i],a[i],otp[i]);
	for(int i=1,op,x,y;i<=n;i++)
	{
		unsigned long long z;
		scanf("%d%d%d%llu",&op,&x,&y,&z);
		if(op==1)printf("%llu\n",gets(x,y,z));
		else modify(1,1,n,nid[x],z,y); 
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值