题目描述:
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。
样例:
样例输入:
20 50
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
(有点长……)
样例输出:
87
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≤109
题解:
看到这道题我首先想到了这道题:BZOJ3631。
对于上面这道题,如果你还没有思路的话可以看一下这篇博客:[BZOJ3631]:[JLOI2014]松鼠的新家(LCA+树上差分)。
然后,我就立马想到了先求出LCA然后进行树上差分,但是这两道题的区别在于,这道题的物品种类不止一个,而且数还不小,显然不能单纯的用树上差分来解决。
于是考虑用权值线段树维护,先将物品种类排序,然后看利用树上差分更新权值线段树,之后递归合并统计答案即可。
代码时刻:
#include<bits/stdc++.h> using namespace std; struct rec//存边 { int nxt; int to; }e[200000]; struct qwq//存操作 { int x; int y; int z; }question[100001]; int head[100001],cnt; int fa[100001][20]; int root[100001],trfal[10000001],trsum[10000001],ls[10000001],rs[10000001],sum,tot; int dfsv[100001]; int depth[100001]; int que[100001]; bool cmp(qwq a,qwq b){return a.z<b.z;}//按物品排序问题 void add(int x,int y)//建边 { e[++cnt].nxt=head[x]; e[cnt].to=y; head[x]=cnt; } void dfs(int x)//dfs预处理父亲和深度 { dfsv[++dfsv[0]]=x; for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa[x][0]) { fa[e[i].to][0]=x; depth[e[i].to]=depth[x]+1; for(int j=1;j<=18;j++) fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1]; dfs(e[i].to); } } int LCA(int x,int y)//倍增求LCA { if(depth[x]<depth[y])swap(x,y); for(int i=18;i>=0;i--) if(depth[fa[x][i]]>=depth[y])x=fa[x][i]; if(x==y)return x; for(int i=18;i>=0;i--) if(fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } void pushup(int x) { trfal[x]=max(trfal[ls[x]],trfal[rs[x]]);//维护的权值 trsum[x]=(trfal[ls[x]]>=trfal[rs[x]])?trsum[ls[x]]:trsum[rs[x]];//哪种物品 } void insert(int &x,int k,int fl,int l,int r) { if(!x)x=++tot; if(l==r) { trfal[x]+=fl; trsum[x]=que[l]; return; } int mid=(l+r)>>1; if(k<=mid)insert(ls[x],k,fl,l,mid); else insert(rs[x],k,fl,mid+1,r); pushup(x); } void ask(int &x,int fl,int l,int r) { if(!fl)return; if(!x) { x=fl; return; } if(l==r) { trfal[x]+=trfal[fl]; return; } int mid=(l+r)>>1; ask(ls[x],ls[fl],l,mid); ask(rs[x],rs[fl],mid+1,r); pushup(x); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)root[i]=i; tot=n; for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } depth[1]=1; dfs(1); for(int i=1;i<=m;i++) scanf("%d%d%d",&question[i].x,&question[i].y,&question[i].z); sort(question+1,question+m+1,cmp); for(int i=1;i<=m;i++) { int lca=LCA(question[i].x,question[i].y); if(question[i].z>question[i-1].z)que[++sum]=question[i].z; insert(root[question[i].x],sum,1,1,m);//树上差分操作 insert(root[question[i].y],sum,1,1,m); insert(root[lca],sum,-1,1,m); if(lca!=1)insert(root[fa[lca][0]],sum,-1,1,m); } for(int i=n;i>1;i--) ask(root[fa[dfsv[i]][0]],root[dfsv[i]],1,m); for(int i=1;i<=n;i++) printf("%d\n",trsum[root[i]]); return 0; }
rp++