zoukankan      html  css  js  c++  java
  • 雨天的尾巴

    Acwing连接(BZOJ3307)

    题面

    深绘里一直很讨厌雨天。

    灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

    虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。

    无奈的深绘里和村民们只好等待救济粮来维生。

    不过救济粮的发放方式很特别。

    有 n 个点,形成一个树状结构。

    有 m 次发放操作,每次选择两个点 x,y,对 x 到 y 的路径上(包括 x,y)的每个点发放一袋 z 类型的物品。

    求完成所有发放操作后,每个点存放最多的是哪种类型的物品。

    输入格式

    第一行两个正整数n,m,含义如题目所示。

    接下来n-1行,每行两个数(a,b),表示(a,b)间有一条边。

    再接下来m行,每行三个数(x,y,z),含义如题目所示。

    输出格式

    共n行,第i行一个整数,表示第i座房屋里存放的最多的是哪种救济粮,如果有多种救济粮存放次数一样,输出编号最小的。

    如果某座房屋里没有救济粮,则对应一行输出0。

    数据范围

    1≤n,m≤100000,
    1≤z≤10^9
    

    输入样例:

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

    输出样例:

    2
    3
    3
    0
    2
    

    题解

    需要掌握 树上LCA 和 动态开点线段树

    思想 差分, 离散化

    根据题意明显是 区间操作, 对于树, 那么就是树上差分 和 树剖 了

    对于 (x, y) 增加 z, 根据差分, 思考发现, ++val[x][z], ++val[y][z], --val[lca(x, y)][z], --val[lca(x, y)的父节点][z], 可以在树上线性跑出 每个节点 z 的数量

    而 z 异常的大, 1e9, 而 m 只有1e5, 明显需要离散化, 降低 z 的范围

    就算如此 对于每个节点 跑出 每个z的数量也是 爆炸的

    我们就要想到 log 级别的方法, 那就线段树了, 然而肯定会爆内存, 所以要动态开点

    对于节点数, 4 * m * log2(z(离散化)), 每个节点占 12字节, 在加上乱七八糟的lca和存输入的数组, 内存也不会太紧张(你要是节点东西多了, 会爆, 还是有点卡内存的)

    #include <bits/stdc++.h>
    #define all(n) (n).begin(), (n).end()
    #define se second
    #define fi first
    #define pb push_back
    #define mp make_pair
    #define sqr(n) (n)*(n)
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define per(i,a,b) for(int i=(a);i>=(b);--i)
    #define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    typedef vector<int> VI;
    typedef double db;
    
    const int N = 1e5 + 5, M = 7e6 + 5;
    
    int n, m, _, k;
    int h[N], ne[N << 1], to[N << 1], tota;
    int dep[N], f[N][20], t;
    int x[N], y[N], z[N], tax[N], tot, ans[N];
    
    void add(int u, int v) {
    	ne[++tota] = h[u]; to[h[u] = tota] = v;
    }
    
    void bfs(int s) {
    	queue<int> q;
    	q.push(s); dep[s] = 1;
    	rep(i, 0, t) f[s][i] = 0;
    
    	while (!q.empty()) {
    		int x = q.front(); q.pop();
    		for (int i = h[x]; i; i = ne[i]) {
    			int y = to[i];
    			if (dep[y]) continue;
    			dep[y] = dep[x] + 1;
    			f[y][0] = x;
    
    			for (int j = 1; j <= t; ++j)
    				f[y][j] = f[f[y][j - 1]][j - 1];
    
    			q.push(y);
    		}
    	}
    }
    
    int lca(int x, int y) {
    	if (dep[x] > dep[y]) swap(x, y);
    	per(i, t, 0)
    		if (dep[f[y][i]] >= dep[x]) y = f[y][i];
    
    	if (x == y) return x;
    
    	per(i, t, 0)
    		if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    
    	return f[x][0];
    }
    
    struct Node {
    	int l, r, mx;
    } tr[M];
    
    int node, rt[N];
    
    void push_up(int root) {
    	tr[root].mx = max(tr[tr[root].l].mx, tr[tr[root].r].mx);
    }
    
    void update(int& root, int l, int r, int val, int d) {
    	if (root == 0) root = ++node;
    	if (l == r) {
    		tr[root].mx += d;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if (mid >= val) update(tr[root].l, l, mid, val, d);
    	else update(tr[root].r, mid + 1, r, val, d);
    	push_up(root);
    }
    
    int merge(int a, int b) {
    	if (a == 0 || b == 0) return a | b;
    	if (tr[a].l == 0 && tr[a].r == 0) {
    		tr[a].mx += tr[b].mx;
    		return a;
    	}
    
    	tr[a].l = merge(tr[a].l, tr[b].l);
    	tr[a].r = merge(tr[a].r, tr[b].r);
    	push_up(a);
    	return a;
    }
    
    int query(int root, int l, int r) {
    	if (root == 0) return 0;
    	if (l == r) return l;
    
    	int mid = (l + r) >> 1;
    	if (tr[tr[root].l].mx == tr[root].mx) return query(tr[root].l, l, mid);
    	else return query(tr[root].r, mid + 1, r);
    }
    
    void dfs(int u, int fa) {
    	for (int i = h[u]; i; i = ne[i]) {
    		int y = to[i];
    		if (y == fa) continue;
    		dfs(y, u);
    		rt[u] = merge(rt[u], rt[y]);
    	}
    
    	ans[u] = tax[query(rt[u], 1, tot)];
    }
    
    int main() {
    	IO; cin >> n >> m;
    	t = log2(n - 1) + 1;
    
    	rep(i, 2, n) {
    		int u, v; cin >> u >> v;
    		add(u, v); add(v, u);
    	}
    	bfs(1);
    
    	rep(i, 1, m) cin >> x[i] >> y[i] >> z[i], tax[i] = z[i];
    	sort(tax + 1, tax + 1 + m);
    	tot = unique(tax + 1, tax + 1 + m) - tax - 1;
    
    	rep(i, 1, m) {
    		int fa = lca(x[i], y[i]), c = lower_bound(tax + 1, tax + tot + 1, z[i]) - tax;
    		update(rt[x[i]], 1, tot, c, 1); update(rt[y[i]], 1, tot, c, 1);
    		update(rt[fa], 1, tot, c, -1); update(rt[f[fa][0]], 1, tot, c, -1);
    	}
    
    	dfs(1, 0);
    	rep(i, 1, n) cout << ans[i] << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    jquery选择器
    js实现添加className
    日期函数(date)
    IE6和IE7中<a>标签宽高设置无效的问题
    Uva 548 二叉树的递归遍历lrj 白书p155
    Uva 122 树的层次遍历 Trees on the level lrj白书 p149
    Uva 679 Dropping Ballls 二叉树的编号
    Uva 12657 Boxes in a Line 双向链表
    Uva 11988 Broken Keyboard STL+链表
    埃及分数问题+迭代加深搜索
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13525201.html
Copyright © 2011-2022 走看看