【题目】
题目背景:
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
题目描述:
首先村落里的一共有 n n n 座房屋,并形成一个树状结构。救济粮分 m m m 次发放,每次选择两个房屋 ( x , y ) (x,y) (x,y),对于 x x x 到 y y y 的路径上(含 x x x 和 y y y)每座房子里发放一袋 z z z 类型的救济粮。
深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
输入格式:
第一行两个正整数 n , m n,m n,m,含义如题目所示。
接下来 n − 1 n-1 n−1 行,每行两个数 ( a , b ) (a,b) (a,b),表示 ( a , b ) (a,b) (a,b) 间有一条边。
再接下来 m m m 行,每行三个数 ( x , y , z ) (x,y,z) (x,y,z),含义如题目所示。
输出格式:
n n n 行,第 i i i 行一个整数,表示第 i i i 座房屋里存放的最多的是哪种救济粮,如果有多种救济粮存放次数一样,输出编号最小的。
如果某座房屋里没有救济粮,则对应一行输出 0 0 0。
样例数据:
输入
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
输出
2
3
3
0
2
说明:
对于
20
%
20\%
20% 的数据,
1
≤
n
,
m
≤
100
1 \le n, m \le 100
1≤n,m≤100
对于
50
%
50\%
50% 的数据,
1
≤
n
,
m
≤
2000
1 \le n, m \le 2000
1≤n,m≤2000
对于
100
%
100\%
100% 的数据,
1
≤
n
,
m
≤
100000
,
1
≤
a
,
b
,
x
,
y
≤
n
,
1
≤
z
≤
100000
1 \le n, m \le 100000, 1 \le a, b, x, y \le n, 1 \le z \le 100000
1≤n,m≤100000,1≤a,b,x,y≤n,1≤z≤100000
【分析】
这道题和城市有点像啊
用树上差分,对于 ( x , y ) (x,y) (x,y) 这条路径,则在 x , y x,y x,y 处 + 1 +1 +1,在 l c a , f a ( l c a ) lca,fa(lca) lca,fa(lca) 处 − 1 -1 −1
那么用线段树合并,在 d f s dfs dfs 时往上合并,其他的地方就和城市那道题一样了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int n,m,t,tot;
int first[N],v[N<<1],nxt[N<<1];
int dep[N],ans[N],root[N],fa[N][25],lc[N<<5],rc[N<<5];
pair<int,int>Max[N<<5];
void add(int x,int y)
{
t++;
nxt[t]=first[x];
first[x]=t;
v[t]=y;
}
void dfs(int x)
{
int i,k;
for(i=1;i<=20;++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(i=first[x];i;i=nxt[i])
{
k=v[i];
if(k!=fa[x][0])
{
fa[k][0]=x;
dep[k]=dep[x]+1;
dfs(k);
}
}
}
int lca(int x,int y)
{
int i;
if(dep[x]<dep[y]) swap(x,y);
for(i=20;~i;--i)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(i=20;~i;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void insert(int &root,int l,int r,int pos,int num)
{
if(!root) root=++tot;
if(l==r)
{
Max[root]=make_pair(Max[root].first+num,-pos);
return;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(lc[root],l,mid,pos,num);
else insert(rc[root],mid+1,r,pos,num);
Max[root]=max(Max[lc[root]],Max[rc[root]]);
}
int Merge(int x,int y,int l,int r)
{
if(!x) return y;
if(!y) return x;
int mid=(l+r)>>1;
if(l==r) return Max[x].first+=Max[y].first,x;
lc[x]=Merge(lc[x],lc[y],l,mid);
rc[x]=Merge(rc[x],rc[y],mid+1,r);
Max[x]=max(Max[lc[x]],Max[rc[x]]);
return x;
}
void Dfs(int x)
{
int i,k;
for(i=first[x];i;i=nxt[i])
{
k=v[i];
if(k!=fa[x][0])
{
Dfs(k);
root[x]=Merge(root[x],root[k],1,N-5);
}
}
ans[x]=-Max[root[x]].second;
}
int main()
{
int x,y,z,i;
scanf("%d%d",&n,&m);
for(i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dep[1]=1,dfs(1);
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&z);
insert(root[x],1,N-5,z,1);
insert(root[y],1,N-5,z,1);
insert(root[lca(x,y)],1,N-5,z,-1);
insert(root[fa[lca(x,y)][0]],1,N-5,z,-1);
}
Dfs(1);
for(i=1;i<=n;++i)
printf("%d\n",ans[i]);
return 0;
}