树剖37pts求助
查看原帖
树剖37pts求助
938950
YGW6楼主2024/7/10 15:44

蒟蒻刚学树剖,麻烦各位dalao帮助一下QAQ

代码37pts,过样例了,#1,#2,#3,#11过了,其余的WA

###代码有部分注释

#include<iostream>
#include<cmath>
#include<string>
#include<string.h>
#include<algorithm>

using namespace std;

const int N=1e5+5;

int n,m,r,mod;
int answer;
int w[N];
int cnt;
int fa[N],dep[N],size[N],son[N],top[N],id[N],wt[N];
/*
fa[u]:u在树中的父亲
dep[u]:u节点的深度
size[u]:u的子树节点数(子树大小)
son[u]:u的重儿子
top[u]:u所在重链的顶部节点
id[x]:新的编号
wt[y]:新编号的点权 
*/

struct edge
{
	int u,v;
}e[N*2];
int h[N*2],tot;

int sum[N*4],lazy[N*4];

void add(int u,int v)
{
	e[++tot].v=v;
	e[tot].u=h[u];
	h[u]=tot;
}

void dfs1(int u,int f,int deep)
{
	dep[u]=deep;    //标记深度 
	fa[u]=f;        //标记节点的父亲 
	size[u]=1;      //记录每个节点子树大小 
	int maxson=-1;  //记录重儿子数量 
	for(int i=h[u];i!=-1;i=e[i].u)
	{
		int v=e[i].v;
		if(v==f)
			continue;
		dfs1(v,u,deep+1);
		size[u]+=size[v];
		if(size[v]>maxson)  //儿子里最多 size 就是重儿子 
		{
			son[u]=v;  //标记u的重儿子为 v 
			maxson=size[v];
		}
	}
}

//处理出top[],wt[],id[] 
void dfs2(int u,int topf)
{
	id[u]=++cnt;   //每个节点的新编号 
	wt[cnt]=w[u];  //新编号的对应权值 
	top[u]=topf;   //标记每个重链的顶端 
	if(!son[u])    //没有儿子时返回 
		return ;
	dfs2(son[u],topf);  //搜索下一个重儿子 
	for(int i=h[u];i!=-1;i=e[i].u)
	{
		int v=e[i].v;
		if(v==fa[u] or v==son[u])  //处理轻儿子 
			continue;
		dfs2(v,v);  //每一个轻儿子都有一个从自己开始的链 
	}
}

void push_up(int u)
{
	sum[u]=(sum[2*u]+sum[2*u+1])%mod;
}

void push_down(int u,int len)  //下放lazy标记 
{
	lazy[2*u]+=lazy[u];
	lazy[2*u+1]+=lazy[u];
	sum[2*u]+=lazy[u]*(len-len/2);
	sum[2*u]%=mod;
	sum[2*u+1]+=lazy[u]*len/2;
	sum[2*u+1]%=mod;
	lazy[u]=0;
}

void build(int u,int l,int r)
{
	lazy[u]=0;
	if(l==r)
	{
		sum[u]=wt[l];  //新的编号点权 
		sum[u]%=mod;
		return ;
	}
	int mid=(l+r)/2;
	build(2*u,l,mid);
	build(2*u+1,mid+1,r);
	push_up(u);
}

void update(int L,int R,int c,int l,int r,int u)
{
	if(L<=l&&R>=r)
	{
		lazy[u]+=c;
		sum[u]+=c*(r-l+1);
		sum[u]%=mod;
		return ;
	}
	if(lazy[u])
		push_down(u,r-l+1);
	int mid=(l+r)/2;
	if(L<=mid)
		update(L,R,c,l,mid,2*u);
	if(R>mid)
		update(L,R,c,mid+1,r,2*u+1);
	push_up(u);
}

void updrange(int x,int y,int k)
{
	k%=mod;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])  //使x深度较大 
			swap(x,y);
		update(id[top[x]],id[x],k,1,n,1);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])  //使x深度较小 
		swap(x,y);
	update(id[x],id[y],k,1,n,1);
}

void query(int L,int R,int l,int r,int u)
{
	if(L<=l&&R>=r)
	{
		answer+=sum[u];
		answer%=mod;
		return ;
	}
	if(lazy[u])
		push_down(u,r-l+1);
	int mid=(l+r)/2;
	if(L<=mid)
		query(L,R,l,mid,2*u);
	if(R>mid)
		query(L,R,mid+1,r,2*u+1);
}

int qrange(int x,int y)
{
	int ans=0;
	while(top[x]!=top[y])  //当两个点不在同一条链上 
	{
		if(dep[top[x]]<dep[top[y]])  //使x深度较大 
			swap(x,y);
		answer=0;
		query(id[top[x]],id[x],1,n,1);  //ans加上x点到x所在链顶端这一段区间的点权和 
		ans+=answer;
		ans%=mod;
		x=fa[top[x]];  //x跳到x所在链顶端的这个点的上面一个点 
	}
	//当两个点处于同一条链 
	if(dep[x]>dep[y])  //使x深度较小 
		swap(x,y);
	answer=0;
	query(id[x],id[y],1,n,1);
	ans+=answer;
	ans%=mod;
	return ans;
}

void upson(int x,int k)
{
	update(id[x],id[x]+size[x]-1,k,1,n,1);  //子树区间右端点为id[x]+siz[x]-1 
}

int qson(int x)
{
	answer=0;
	query(id[x],id[x]+size[x]-1,1,n,1);
	return answer;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>r>>mod;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;i++)
		cin>>w[i];
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs1(r,0,1);  //根节点,父亲,深度 
	dfs2(r,r);
	build(1,1,n);  //用新点权建立线段树 
	while(m--)
	{
		int op,x,y,z;
		cin>>op;
		if(op==1)
		{
			cin>>x>>y>>z;
			updrange(x,y,z);
		}
		else if(op==2)
		{
			cin>>x>>y;
			cout<<qrange(x,y)<<endl;
		}
		else if(op==3)
		{
			cin>>x>>z;
			upson(x,z);
		}
		else if(op==4)
		{
			cin>>x;
			cout<<qson(x)<<endl;
		}
	}
	return 0;
}
2024/7/10 15:44
加载中...