3307: 雨天的尾巴
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 654 Solved: 270
[Submit][Status][Discuss]
Description
N個點,形成一個樹狀結構。有M次發放,每次選擇兩個點x,y
對於x到y的路徑上(含x,y)每個點發一袋Z類型的物品。完成
所有發放後,每個點存放最多的是哪種物品。
Input
第一行數字N,M
接下來N-1行,每行兩個數字a,b,表示a與b間有一條邊
再接下來M行,每行三個數字x,y,z.如題
Output
輸出有N行
每i行的數字表示第i個點存放最多的物品是哪一種,如果有
多種物品的數量一樣,輸出編號最小的。如果某個點沒有物品
則輸出0
Sample Input
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
Sample Output
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9
HINT
Source
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
inline int read(){
int x=0, res=1; char c=getchar();
while(!(c>='0'&&c<='9')){ if(c=='-') res=-1; c=getchar(); }
while(c>='0'&&c<='9') x=x*10+c-'0', c=getchar();
return x*res;
}
const int N=100010;
int n, m, tot, di, dti;
int head[N], wch[N], ans[N];
int dep[N], size[N], fa[N], son[N], dfn[N], Rank[N], top[N];
map <int,int> kind;
struct Edge{int to, next; }e[N<<1];
struct Data{int z, next, val; }dt[N*30];
struct Node{int typ, num; }nd[N<<2];
inline void add_edge(int u,int v){
e[++tot] = (Edge){v,head[u]}; head[u]=tot;
e[++tot] = (Edge){u,head[v]}; head[v]=tot;
}
inline void add_data(int u,int v,int val){
dt[++dti] = (Data){v,head[u],val}; head[u]=dti;
}
void dfs1(int u){
size[u] = 1;
for(int p=head[u], v; p; p=e[p].next){
v = e[p].to;
if(v==fa[u]) continue;
dep[v] = dep[u]+1; fa[v] = u;
dfs1(v);
size[u] += size[v];
if(son[u]==0 || size[son[u]]<size[v]) son[u]=v;
}
}
void dfs2(int u,int tp){
top[u] = tp; dfn[u] = ++di; Rank[di] = u;
if(son[u]) dfs2(son[u], tp);
for(int p=head[u]; p; p=e[p].next) if(e[p].to!=fa[u] && e[p].to!=son[u]) dfs2(e[p].to,e[p].to);
}
inline bool cmp(Node &x,Node &y){
return (x.num<y.num) || (x.num==y.num && wch[x.typ]>wch[y.typ]);
}
inline void merge(int rt){
nd[rt].num = -1;
if(cmp(nd[rt],nd[rt<<1])){ nd[rt].num=nd[rt<<1].num; nd[rt].typ=nd[rt<<1].typ; }
if(cmp(nd[rt],nd[rt<<1|1])){ nd[rt].num=nd[rt<<1|1].num; nd[rt].typ=nd[rt<<1|1].typ; }
}
void build(int l,int r,int rt){
if(l==r) nd[rt].typ=r, nd[rt].num=0;
else{
int mid = l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
merge(rt);
}
}
void change(int l,int r,int rt,int x,int val){
if(l==r) nd[rt].num+=val;
else{
int mid = l+r>>1;
if(x<=mid) change(l,mid,rt<<1,x,val);
else change(mid+1,r,rt<<1|1,x,val);
merge(rt);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1; i<n; ++i){ add_edge(read(), read()); }
dep[1] = 1; dfs1(1); dfs2(1,1);
memset(head,0,sizeof(head)); tot=0; // 當這棵樹有了靈魂(dep,fa,top,dfn,Rank),它的框架就可以清空了
for(int i=1, u, v, z, fu, fv; i<=m; ++i){
u=read(); v=read(); z=read(); fu=top[u]; fv=top[v];
if(!kind.count(z)) kind[z]=++tot, wch[tot]=z; // 用 map 來進行物品種類的離散化
z = kind[z];
// 用圖儲存操作
while(fu!=fv){
if(dep[fu]<dep[fv]){
add_data(dfn[fv],z,1); add_data(dfn[v]+1,z,-1);
v=fa[fv]; fv=top[v];
}else{
add_data(dfn[fu],z,1); add_data(dfn[u]+1,z,-1);
u=fa[fu]; fu=top[u];
}
}
if(dfn[u]>dfn[v]) swap(u,v);
add_data(dfn[u],z,1); add_data(dfn[v]+1,z,-1);
}
build(1,tot,1); // 建一棵維護物品數和種類的線段樹
for(int i=1, p; i<=n; ++i){
for(p=head[i]; p; p=dt[p].next) change(1,tot,1,dt[p].z,dt[p].val); // 讓整棵樹爲當前這個點服務
ans[Rank[i]] = nd[1].num ? nd[1].typ : 0;
}
for(int i=1; i<=n; ++i) printf("%d\n",wch[ans[i]]);
}