清北学堂-计树-树剖-动态开点

大兔子大兔子 提交于 2019-11-27 10:52:26

输入样例:

3
5 5
3 2 1 1 1
1 2
2 3
2 5
3 4
2 3 4 1
1 2 1
2 3 5 1
2 1 5 3
2 4 4 3
5 5
1 2 1 2 2
1 2
2 3
2 4
3 5
1 1 2
1 3 2
1 2 2
2 4 2 2
2 1 4 1
5 5
2 1 1 1 1
1 2
1 4
2 3
4 5
2 4 2 1
1 1 1
2 1 4 1
2 3 3 1
2 2 2 2

输出样例:

2
3
1
0
2
0
2
2
1
0

  

数据范围:

思路:

树剖,动态开点,线段树

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 100500
using namespace std;
inline int read() {
	int x = 0,f = 1;
	char s = getchar();
	while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
	while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
	return x * f;
}
int T,n,m;
int head[N * 2],cnt,pos;
struct node { int nxt,to; }e[N * 2];
int tpos[N],top[N],fa[N],wson[N];
int size[N],dep[N],tot,a[N],root[200];
struct tree {
	int l,r,num;	
}tr[N * 400];
inline void cp(int u,int v) {
	cnt ++;
	e[cnt].to = v;
	e[cnt].nxt = head[u];
	head[u] = cnt;
}
inline void dfs1(int u,int f)
{
	size[u] = 1;
	for(int i = head[u]; i ; i = e[i].nxt) {
		int v = e[i].to;
		if(v == f) continue;
		fa[v] = u; dep[v] = dep[u] + 1;
		dfs1(v,u); size[u] += size[v];
		if(size[v] > size[wson[u]]) wson[u] = v;
	}
}
inline void dfs2(int u,int Top) {
	tpos[u] = ++ tot;
	top[u] = Top;
	if(wson[u]) dfs2(wson[u],Top);
	for(int i = head[u]; i ; i = e[i].nxt) {
		int v = e[i].to;
		if(v == wson[u] || v == fa[u]) continue;
		dfs2(v,v);
	} 
}
inline void update(int k)
{
	tr[k].num = tr[tr[k].l].num + tr[tr[k].r].num;
}
inline void change(int &k,int l,int r,int x,int y) {
	if(!k) k = ++ pos; 
	if(l == r) {
		tr[k].num = y;
		return ;
	}
	int mid = (l + r) >> 1;
	if(x <= mid) change(tr[k].l,l,mid,x,y);
	if(x > mid) change(tr[k].r,mid + 1,r,x,y);
	update(k);
}
inline int ask(int k,int l,int r,int a,int b) {
	if(!k) return 0;
	if(l >= a && r <= b) return tr[k].num;
	int mid = (l + r) >> 1,res = 0;
	if(a <= mid) res += ask(tr[k].l,l,mid,a,b);
	if(b > mid) res += ask(tr[k].r,mid + 1,r,a,b);
	return res;
}
inline int tr_ask(int u,int v,int col) {
	int res = 0;
	while(top[u] != top[v]) {
		if(dep[top[u]] < dep[top[v]]) swap(u,v);
		res += ask(root[col],1,n,tpos[top[u]],tpos[u]);
		u = fa[top[u]];
	}
	if(dep[u] > dep[v]) swap(u,v);
	res += ask(root[col],1,n,tpos[u],tpos[v]);
	return res;
}
inline void delldate(int k) {
	tr[k].num = (tr[tr[k].l].num + tr[tr[k].r].num);
	tr[k].l = tr[k].r = 0;
}
inline void dell(int k,int l,int r) {
	if(!k) return ;
	if(l == r) {
		tr[k].num = 0;
		return ;
	}
	int mid = (l + r) >> 1;
	dell(tr[k].l,l,mid); dell(tr[k].r,mid + 1,r);
	delldate(k);
}
inline void Work() {
	n = read(); m = read();
	for(int i = 1;i <= n;i ++) a[i] = read();
	for(int i = 1;i <= n - 1;i ++) {
		int a = read(),b = read();
		cp(a,b),cp(b,a);
	}
	fa[1] = 1,dep[1] = 1;
	dfs1(1,-1);
	dfs2(1,1);
	for(int i = 1;i <= n;i ++)change(root[a[i]],1,n,tpos[i],1);
	for(int i = 1;i <= m;i ++) {
		int tmp = read();
		if(tmp == 1) 
		{
			int u = read(),x = read();
			change(root[a[u]],1,n,tpos[u],0);
			a[u] = x;
			change(root[a[u]],1,n,tpos[u],1);
		}
		if(tmp == 2)
		{
			int u = read(),v = read(),x = read();
			printf("%d\n",tr_ask(u,v,x));
		}
	}
}
inline void Clean() {
	for(int i = 1;i <= 110;i ++)dell(root[i],1,n),root[i] = 0;
	memset(head,0,sizeof(head)); 
	memset(fa,0,sizeof(fa));
	memset(tpos,0,sizeof(tpos));
	memset(top,0,sizeof(top)); 
	memset(wson,0,sizeof(wson));
	memset(size,0,sizeof(size));
	memset(dep,0,sizeof(dep));
	cnt = tot = pos = 0; 
}
int main() {
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	T = read();
	while(T --)
	{
		Work();
		Clean();
	}
	return 0;
}

  完毕--yilin

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!