dsu on tree + 线段树求调
查看原帖
dsu on tree + 线段树求调
530349
天空即为极限楼主2022/9/4 15:01
#include<bits/stdc++.h>
using namespace std;
int col[1000005], ans[1000005];
const int N = 2e5 + 5;
vector<int> v[100005];
vector<pair<int, int> > ask[100005];
int cnt[1000005];
bool vis[1000005];
struct node{
	int dep, size, son;
}Node[1000005];
struct point{
	int l, r, sum;
}seg[4000005];
int heavy, tot, root, type, n, m;
void dfs(int x, int fa){
	Node[x].dep = Node[fa].dep + 1, Node[x].size = 1;
	for(int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if(to == fa) continue;
		dfs(to, x); Node[x].size += Node[to].size;
		if(Node[Node[x].son].size < Node[to].size) Node[x].son = to;
	}
}

void pushup(int cur) {
	seg[cur].sum = seg[seg[cur].l].sum + seg[seg[cur].r].sum;
}

void insert(int &cur, int l, int r, int x, int val) {
	if(!cur) cur = ++tot;
	if(l == r) { seg[cur].sum += val; return; }
	int mid = (l + r) >> 1;
	if(x <= mid) insert(seg[cur].l, l, mid, x, val);
	else insert(seg[cur].r, mid + 1, r, x, val);
	pushup(cur);
}

int Ask(int cur, int l, int r, int L, int R){
	if(!cur) return 0;
	if(l >= L and r <= R) return seg[cur].sum;
	int mid = (l + r) >> 1, ans = 0;
	if(L <= mid) ans += Ask(seg[cur].l, l, mid, L, R);
	if(R > mid) ans += Ask(seg[cur].r, mid + 1, r, L, R);
	return ans; 
} 

void update(int x, int fa, int val){
	cnt[col[x]] += val; //cout << Node[x].dep << "\n";
	insert(root, 1, N, cnt[col[x]] - val, -1);
	insert(root, 1, N, cnt[col[x]], 1);
	for(int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if(to == heavy or to == fa) continue;
		update(to, x, val);
	} 
}

void get_ans(int x){
	//	cout << x << ": ";
	//for(int i = 1; i <= n; i++) cout << cnt[Node[i].dep] << " ";
	//puts("");
	for(int i = 0; i < ask[x].size(); i++) {
		pair<int, int> to = ask[x][i];
		ans[to.first] = Ask(root, 1, N, to.second, N);
	}
}

void dfs2(int x, int fa, int flag){
	for(int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if(to == fa or to == Node[x].son) continue;
		dfs2(to, x, 0);
	}
	if(Node[x].son) dfs2(Node[x].son, x, 1), heavy = Node[x].son;
	//	for(int i = 1; i <= n; i++) cout << cnt[Node[i].dep] << " ";
	update(x, fa, 1);
	get_ans(x);
	heavy = 0;
	if(!flag) update(x, fa, -1);  
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		cin >> col[i];
		if(vis[col[i]] == 0) type++;
		vis[col[i]]++;
	}
	for(int i = 1; i <= n - 1; i++) {
		int x, y; cin >> x >> y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	for(int i = 1; i <= m; i++) {
		int x, y; cin >> x >> y;
		ask[x].push_back(make_pair(i, y));
	}
	dfs(1, 0);
	insert(root, 1, N, 0, type);
	dfs2(1, 0, 0);
	for(int i = 1; i <= m; i++) cout << ans[i] << "\n";
}

思路是dsu on tree再用权值线段树求大于等于k的颜色

2022/9/4 15:01
加载中...