• P4556 [Vani有约会]雨天的尾巴 /[模板] 线段树合并


    树上差分 + 线段树合并
    以每个点为根节点建立一棵权值线段树记录now(当前最多的粮食的种类) 和 size(最多的粮食的数量)
    每棵线段树的叶节点 的下标就是粮食的种类a
    最后合并每棵权值线段树就好啦

    #include <bits/stdc++.h>
    using namespace std;
    #define mid (l + r) / 2
    const int N = 1e5 + 5;
    
    int n, m, cnt, tot, t;
    int to[N << 1], head[N], nex[N << 1];
    int ans[N], deep[N], f[N][50];
    int ls[N * 80], rs[N * 80], root[N], size[N * 80], now[N * 80];
    
    void add(int x, int y) {
    	nex[++cnt] = head[x];
    	to[cnt] = y;
    	head[x] = cnt;
    }
    void dfs(int x, int dep) {
    	deep[x] = dep;
    	for(int i = 1; i <= t; i++)
    		f[x][i] = f[f[x][i - 1]][i - 1];
    	for(int i = head[x]; i; i = nex[i]) {
    		int y = to[i];
    		if(deep[y]) continue;
    		f[y][0] = x;
    		dfs(y, dep + 1);
    	}
    }
    int LCA(int x, int y) {
    	if(deep[x] > deep[y]) swap(x, y);
    	for(int i = t; i >= 0; i--)
    		if(deep[f[y][i]] >= deep[x]) y = f[y][i];
    	if(x == y) return x;
    	for(int i = t; i >= 0; i--)
    		if(f[y][i] != f[x][i]) x = f[x][i], y = f[y][i];
    	return f[x][0];
    }
    void up(int x) {
    	if(size[ls[x]] >= size[rs[x]])
    		size[x] = size[ls[x]], now[x] = now[ls[x]];
    	else size[x] = size[rs[x]], now[x] = now[rs[x]];
    }
    int merge(int x, int y, int l, int r) { // 合并操作
    	if(!x || !y) return x + y;
    	if(l == r) {
    		size[x] += size[y];
    		now[x] = l;
    		return x;
    	}
    	ls[x] = merge(ls[x], ls[y], l, mid);
    	rs[x] = merge(rs[x], rs[y], mid + 1, r);
    	up(x);
    	return x;
    }
    void change(int &u, int l, int r, int num, int k) { 
    	if(!u) u = ++tot;
    	if(l == r) {
    		size[u] += k;
    		now[u] = l;
    		return ;
    	}
    	if(num <= mid) change(ls[u], l, mid, num, k);
    	else change(rs[u], mid + 1, r, num, k);
    	up(u);
    }
    void cacl(int x) { // 合并每一棵线段树
    	for(int i = head[x]; i; i = nex[i]) {
    		int y = to[i];
    		if(y == f[x][0]) continue;
    		cacl(y);
    		root[x] = merge(root[x], root[y], 1, N - 5);
    	}
    	if(size[root[x]] && now[root[x]]) ans[x] = now[root[x]];
    	else ans[x] = 0;
    }
    int main() {
    	ios :: sync_with_stdio(0);
    
    	cin >> n >> m;
    	t = (log(n) / log(2)) + 1;
    	for(int i = 1; i < n; i++) {
    		int a, b;
    		cin >> a >> b;
    		add(a, b);
    		add(b, a);
    	}
    	dfs(1, 1);
    	for(int i = 1; i <= m; i++) {
    		int x, y, z;
    		cin >> x >> y >> z;
    		int lca = LCA(x, y);
    		change(root[x], 1, N - 5, z, 1); //  z <= 1e5
    		change(root[y], 1, N - 5, z, 1);
    		change(root[lca], 1, N - 5, z, -1);
    		change(root[f[lca][0]], 1, N - 5, z, -1);
    	}
    	cacl(1);
    	for(int i = 1; i <= n; i++) cout << ans[i] << endl;
    	return 0;
    }
    
  • 相关阅读:
    改进的二分查找
    关于Java并发编程的总结和思考
    java异常捕获案例,此题的出处是《Java编程思想》一书
    一道关于int和Integer的面试题
    看《韩顺平Java》视频的笔记
    spring task 定时任务执行两次
    记录
    Java基础面试题
    TeamViewer修改绑定设备
    jqGrid常用操作
  • 原文地址:https://www.cnblogs.com/hyxss/p/13827054.html
Copyright © 2020-2023  润新知