社区讨论

10pts求助,玄关*2

P3384【模板】重链剖分 / 树链剖分参与者 2已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@mhjuyrt0
此快照首次捕获于
2025/11/04 08:56
4 个月前
此快照最后确认于
2025/11/04 08:56
4 个月前
查看原帖
只AC了最后一个点
用测试点一数据自测,只对了第一次输出
CPP
#include<bits/stdc++.h>
using namespace std;
# define int long long 
const int N = 1e5+10;
// 建树
struct Edge
{
	int to;
	int Next;
}edge[N<<1];
int head[N+1];
int cnt=0;

int res,ans;
int n,m,r,MOD;

void add(int from, int to)
{
	edge[++cnt].to = to;
	edge[cnt].Next = head[from];
	head[from] = cnt;
}

int fa[N],d[N],son[N],siz[N],top[N],w[N],nid[N],nw[N];
//树剖
void DFS1(int now,int dad)
{
	fa[now] = dad;
	siz[now] = 1;
	son[now] = 0;
	d[now] = d[dad] + 1;
	for(int i = head[now]; i; i = edge[i].Next)
	{
		if(edge[i].to == dad)
			continue;
		DFS1(edge[i].to, now);
		
		siz[now] += siz[edge[i].to];
		
		if(siz[son[now]] < siz[ edge[i].to ])
			son[now] = edge[i].to;
	}
}

void DFS2(int now,int Top)
{
	top[now] = Top;
	nid[now] = ++cnt;
	nw[nid[now]] = w[now];
	
	if(son[now])
		DFS2(son[now], Top);
	else
		return;
	
	for(int i = head[now]; i; i = edge[i].Next)
	{
		if(edge[i].to != fa[now] && edge[i].to != son[now])
			DFS2(edge[i].to, edge[i].to);
	}
}

// 建线段树

struct SegmentTree
{
	int l,r;
	long long dat;
	long long add;
} t[N<<2];

void bulid(int l,int r,int p)
{
	t[p].l = l;
	t[p].r = r;
	
	if(l == r)
	{
		t[p].dat = nw[l];
		return;
	}
	
	int mid = (l + r) / 2;
	bulid(l,mid,p*2);
	bulid(mid+1,r,p*2+1);
	t[p].dat = t[p*2].dat + t[p*2+1].dat;
}

void spread(int p)
{
	if(t[p].add&&t[p].l!=t[p].r)
	{
		int mid=(t[p].l+ t[p].r)/2;
		t[p*2].add += t[p].add; 
		t[p*2+1].add += t[p].add;
		t[p*2].dat +=  (mid-t[p].l+1)*t[p].add;
		t[p*2+1].dat +=  (t[p].r-mid)*t[p].add;
	}
	t[p].add = 0;
}
void change(int l,int r,int add,int p)
{
	if(l <= t[p].l && t[p].r <= r)
	{
		t[p].add += add;
		t[p].dat += (t[p].r-t[p].l+1)*add;
		return ;
	}
	
	spread(p);
	
	int mid = (t[p].l + t[p].r) / 2;
	if(l <= mid)
		change(l,mid,add,p*2);
	if(mid < r)
		change(mid+1,r,add,p*2+1);
	t[p].dat = t[p*2].dat + t[p*2+1].dat;
}
long long  ask(int l,int r,int p)
{
	if(l <= t[p].l && t[p].r <= r)
		return t[p].dat;
	spread(p);
	
	int mid = (t[p].l + t[p].r) / 2;
	long long dat=0;
	if(l <= mid)
		dat += ask(l,mid,p*2);
	if(mid < r)
		dat += ask(mid+1,r,p*2+1);
	
	return dat;
}
// 利用LCA->最短路操作
int LCA(int x,int y,int op,int z)
{
	if(op==2)//sum
	{
		ans = 0;
		while(top[x] != top[y])
		{
			if(d[top[x]] < d[top[y]])
				swap(x,y);
			ans += ask(nid[top[x]],nid[x],1);
			x = fa[top[x]];
		}
		if(d[x] > d[y])
			swap(x,y);
		ans += ask(nid[y],nid[x],1);
		return ans;
	}
	else//change
	{
		while(top[x] != top[y])
		{
			if(d[top[x]] < d[top[y]])
				swap(x,y);
			change(nid[top[x]],nid[x],z,1);
			x = fa[top[x]];
		}
		if(d[x] > d[y])
			swap(x,y);
		change(nid[x],nid[y],z,1);
		return 0;
	}
	
}
// 子树操作
long long asksontree(int x)
{
	return ask(nid[x],nid[x]+siz[x]-1,1);
}
void changesontree(int x,int add)
{
	change(nid[x],nid[x]+siz[x]-1,add,1);
}
signed main()
{
	cin>>n>>m>>r>>MOD;
	
	for(int i = 1; i<= n; i++)
		cin >> w[i];
	
	for(int i = 1,f,t; i < n; i++)
	{
		cin>>f>>t;
		add(f,t);
		add(t,f);
	}
	cnt=0;
	DFS1(r,0);
	DFS2(r,r);
	bulid(1,n,1);
	for(int i=1,op,l,r,add;i<=m;i++)
	{
		cin>>op>>l;
		if(op!=4)
		{
			cin>>r;
			if(op==1)
			{
				cin>>add;
				LCA(l,r,op,add);
			} else
				if(op==2)
					cout<<LCA(l,r,op,0)%MOD<<endl; else
						if(op==3)	
							changesontree(l,r);
		}
		else
			cout<<asksontree(l)%MOD<<endl;
	}
}

回复

1 条回复,欢迎继续交流。

正在加载回复...