题意:给出一棵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
#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 pairP;
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 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 ;
}
MID
if(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;
}