HDU

来源:互联网 发布:js async false 编辑:程序博客网 时间:2024/06/13 18:59

题意:给出一棵n个节点的树,和m次操作。 操作a,b,k相当于将树上a,b结点间的路径上的节点都加上一个type k,最后输出每个结点被加最多次的那个type, 若有多个type被加的次数相同,输出编号最小的type。

思路:显然要先树链剖分将树上操作变成线性序列的操作,emmm,然后我就不会了。。

正解:树链剖分后考虑如何维护更新操作,对于一个操作a,b,k,我们可以在pos[a]位置打上一个k标记,在pos[b]位置打上一个-k标记,这里pos[]为树链剖分后的新编号,同一个点的多个标记用vector存储,这里要注意的是,由于我们要更新a->b路径上所有点,因此要给这条树链剖分出来的所有的重链的首尾两端打上标记(不完整的重链就打到结束处),至于为什么只打首尾点,我们后面说。

将所有标记都打完以后,我们就要开始用线段树维护每种type的被加次数了,从pos[1]开始更新线段树,先将pos[1]位置的所有正值对应的type在线段树中+1,然后询问最大值被加次数对应的type,这里因为每次都是询问最大被加次数对应的type,因此我们push up 以后直接输出线段树第一个节点的值就好了,然后再将pos[1]位置的所有负值对应的type在线段树中-1。  对pos[2]重复上面的操作,直到最后所有答案就都求出来了。


考虑上面的做法,如果我们能把整个a->b的树链做成一个连续的序列,那么我们只需在这个序列的首尾各加一个标记就能实现差分询问了,但是由于时间空间限制我们不可能每次将这个树链取出来,也不可能把所有树链都存下来,但是我们有树链剖分这种好东西呀,我们虽然不能把a->b的序列做成一个连续的序列,但是我们可以把它做成logn个连续的序列呀,然后在这logn个连续的序列头尾打标记就好了。

这种差分的思想真的是非常妙啊!

代码:

#include<bits/stdc++.h>#define ll long long#define rank Rank#define MAXN 100010#define inf 0x3f3f3f3f#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1#define MID int mid = (l + r) >> 1; using namespace std;typedef pair<int,int>P;int fa[MAXN], pos[MAXN], rank[MAXN], son[MAXN], sz[MAXN];int top[MAXN], dep[MAXN], ans[MAXN];int num[MAXN << 2], MAX[MAXN << 2];int tid;vector<int> mp[MAXN], Q[MAXN];void init(int n){tid = 0;for(int i = 0; i <= n; i++) mp[i].clear(), Q[i].clear();memset(son, -1, sizeof(int) * (n + 5));memset(num, 0, sizeof(num));memset(MAX, 0, sizeof(MAX));}void dfs1(int u){sz[u] = 1;int v;for(int i = 0; i < mp[u].size(); i++){v = mp[u][i];if(v == fa[u]) continue;fa[v] = u; dep[v] = dep[u] + 1;dfs1(v);sz[u] += sz[v];if(son[u] == -1 || sz[v] > sz[son[u]])son[u] = v;}}void dfs2(int u, int head){top[u] = head;pos[u] = ++tid;rank[tid] = u;if(son[u] == -1) return ;dfs2(son[u], head);int v;for(int i = 0; i < mp[u].size(); i++){v = mp[u][i];if(v == son[u] || v == fa[u]) continue;dfs2(v, v);}}void push_up(int rt){num[rt] = max(num[rt << 1], num[rt << 1 | 1]);if(num[rt << 1] >= num[rt << 1 | 1]) MAX[rt] = MAX[rt << 1];else MAX[rt] = MAX[rt << 1 | 1];}void update(int id, int x, int l, int r, int rt){if(l == r){num[rt] += x;MAX[rt] = id;return ;}MIDif(id <= mid)update(id, x, lson);if(id > mid)update(id, x, rson);push_up(rt);}void work(int u, int v, int w){int f1 = top[u], f2 = top[v];while(f1 != f2){if(dep[f1] < dep[f2])swap(f1, f2), swap(u, v);Q[pos[f1]].push_back(w);Q[pos[u]].push_back(-w);u = fa[f1], f1 = top[u];}if(dep[u] > dep[v]) swap(u, v);Q[pos[u]].push_back(w);Q[pos[v]].push_back(-w);}void solve(int n, int N){for(int i = 1; i <= n; i++){for(int j = 0; j < Q[i].size(); j++)if(Q[i][j] > 0) update(Q[i][j], 1, 1, N, 1);ans[rank[i]] = MAX[1];for(int j = 0; j < Q[i].size(); j++)if(Q[i][j] < 0) update(-Q[i][j], -1, 1, N, 1);}for(int i = 1; i <= n; i++)printf("%d\n", ans[i]);}int main(){int n, m, u, v, w;while(~scanf("%d %d", &n, &m), n + m){init(n);for(int i = 1; i < n; i++){scanf("%d %d", &u, &v);mp[u].push_back(v);mp[v].push_back(u);}fa[1] = dep[1] = 0;dfs1(1);dfs2(1, 1);int up = 0;while(m--){scanf("%d %d %d", &u, &v, &w);work(u, v, w);up = max(w, up);}solve(n, up);}    return 0;}