树剖10分求助
查看原帖
树剖10分求助
701221
Chr0n1CleC楼主2022/8/26 16:21
#include<stdio.h>
#define N 200009
#define ls (p << 1)
#define rs ((p << 1) + 1)
#define int long long

int a[N], head[N], cnt, mod, n, tot;

struct node
{
	int v, nxt;
}e[N << 1];

int fa[N], deep[N], siz[N], hson[N], top[N], dfn[N], b[N];

void dfs1(int u, int fath)
{
	siz[u] = 1;//树大小
	hson[u] = -1;//重儿子
	deep[u] = deep[fath] + 1;//加深度
	fa[u] = fath;//找爸爸
	for (int i = head[u];i;i = e[i].nxt)
		if (fath != e[i].v)
		{
			dfs1(e[i].v, u), siz[u] += siz[e[i].v];
			if (hson[u] == -1 || siz[e[i].v] > siz[hson[u]])
				 hson[u] = e[i].v;//找重儿子
		}
}

inline void add(int u, int v)
{
	e[++ cnt].v = v, e[cnt].nxt = head[u];
	head[u] = cnt;
}

void dfs2(int u, int fath)
{
	top[u] = fath;//确定链首
	dfn[u] = ++ tot;//dfs序
	a[tot] = b[u];//按dfn序的新序列(压缩成序列)
	if (hson[u] == -1)//没得
		return;
	dfs2(hson[u], fath);//重链处理
	for (int i = head[u];i;i = e[i].nxt)//轻链处理
		if (!dfn[e[i].v])//不能算重复的
			dfs2(e[i].v, e[i].v);//链开始
}

//-----------------------------------------//-----------------------------------------

int tree[N << 2], lazy[N << 2];//线段树

inline void pushdown(int l, int r, int p)
{
	int mid = (l + r) >> 1;
	tree[ls] = (tree[ls] + (lazy[ls] = (lazy[p] + lazy[ls]) % mod) * (mid - l + 1)) % mod;
	tree[rs] = (tree[rs] + (lazy[rs] = (lazy[p] + lazy[rs]) % mod) * (r - mid)) % mod;
	lazy[p] = 0;
}

void build(int l, int r, int p)
{
	if (l == r)
	{
		tree[p] = a[l] % mod;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, ls);
	build(mid + 1, r, rs);
	tree[p] = (tree[ls] + tree[rs]) % mod;
}

void updata(int sl, int sr, int l, int r, int p, int k)
{
	
	if (l >= sl && r <= sr)
	{
		lazy[p] = (lazy[p] + k) % mod;
		tree[p] = (tree[p] + k * (r - l + 1)) % mod;
		return;
	}
	if (lazy[p])
		pushdown(l, r, p);
	int mid = (l + r) >> 1;
	if (sl <= mid)
		updata(sl, sr, l, mid, ls, k);
	if (sr > mid)
		updata(sl, sr, mid + 1, r, rs, k);
	tree[p] = (tree[ls] + tree[rs]) % mod;
}

int query(int sl, int sr, int l, int r, int p)
{
	if (l >= sl && r <= sr)
		return tree[p];
	if(lazy[p])
		pushdown(l, r, p);
	int mid = (l + r) >> 1, ret = 0;
	if (sl <= mid)
		ret = query(sl, sr, l, mid, ls);
	if (sr > mid)
		ret += query(sl, sr, mid + 1, r, rs);
	return ret % mod;
}

//-----------------------------------------//-----------------------------------------

inline void swap(int& a, int& b) {int c = a;a = b, b = c;}

inline void change(int u, int v, int x)
{	
	x %= mod;
	while (top[u] != top[v])
	{
		if (deep[top[u]] < deep[top[v]])
			swap(u, v);
		updata(dfn[top[u]], dfn[u], 1, n, 1, x);//对链操作
		u = fa[top[u]];
	}
	if (dfn[u] > dfn[v])
		swap(u, v);
	updata(dfn[u], dfn[v], 1, n, 1, x);
}

inline void ask(int u, int v)
{
	int ans = 0;
	while (top[u] != top[v])//不在一条链
	{
		if (deep[top[u]] < deep[top[v]])
			swap(u, v);
		ans = (query(dfn[top[u]], dfn[u], 1, n, 1) + ans) % mod;
		u = fa[top[u]];//出链
	}
	if (dfn[u] > dfn[v])
		swap(u, v);
	printf("%lld\n", (query(dfn[u], dfn[v], 1, n, 1) + ans) % mod);
}

inline void change1(int u, int x)
{
	updata(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1, x % mod);
}

inline void ask1(int u)
{
	printf("%lld\n", query(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1));
}
	
signed main()
{
	int m, r;
	scanf("%lld%lld%lld%lld", &n, &m, &r, &mod);
	for (int i = 1;i <= n;i ++)
		scanf("%lld", &b[i]), b[i] %= mod;
	int u, v;
	for (int i = 1;i < n;i ++)
		scanf("%lld%lld", &u, &v), add(u, v), add(v, u);
	dfs1(r, 0);
	dfs2(r, r);
	build(1, n, 1);
	int opt, x;
	while (m --)
	{
		scanf("%lld%lld", &opt, &u);
		if (opt == 1)
			scanf("%lld%lld", &v, &x), change(u, v, x);
		if (opt == 2)
			scanf("%lld", &v),  ask(u, v);
		if (opt == 3)
			scanf("%lld", &x), change1(u, x);
		if (opt == 4)
			ask1(u);
	}
	
	return 0;
}
2022/8/26 16:21
加载中...