[线段树][树上差分] Jzoj P3397 雨天的尾巴

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

5 3
1 2
3 1
3 4
5 4
2 3 3
1 5 2
3 3 3

Sample Output

2
3
3
2
2

Data Constraint

对于20% 的数据,1<= n,m <= 100

对于50% 的数据,1 <= n,m <= 2000

对于100% 的数据,1 <= n;m <= 100000; 1 <= a, b, x, y <= n; 1 <= z <= 10^9

 

题解

  • 考虑如果是在一条链上的话要怎么做
  • 那么我们可以在x处加一个加入z的标记,在y+1出加入一个删掉z的标记,然后用权值线段树扫一遍就好了
  • 现在拓展到一棵树上,我们可以在x和y处加入一个加上z的标记,在lca和fa[lca]处加入一个删除z的标记,那么我们每次可以把子节点的线段树合并上来
  • 然后处理标记信息,最后查询答案即可

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <vector>
 5 #define N 100010
 6 using namespace std;
 7 struct tree { int l,r,sum,v; }t[N*50];
 8 int n,m,cnt,deep[N],a[N],root[N],fa[N][18],ans[N];
 9 vector<int>e[N],p[N],q[N];
10 void pushup(int x) { if (t[t[x].r].sum>t[t[x].l].sum) t[x].sum=t[t[x].r].sum,t[x].v=t[t[x].r].v; else t[x].sum=t[t[x].l].sum,t[x].v=t[t[x].l].v; }
11 void dfs(int x,int f,int dep)
12 {
13     fa[x][0]=f,deep[x]=dep,root[x]=x,cnt++;
14     for (int i=1;i<=17;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
15     for (int i=0;i<e[x].size();i++) if (e[x][i]!=f) dfs(e[x][i],x,dep+1);    
16 }
17 int LCA(int x,int y)
18 {
19     if (deep[x]<deep[y]) swap(x,y);
20     for (int i=17;i>=0;i--) if (deep[fa[x][i]]>=deep[y]) x=fa[x][i];
21     if (x==y) return x;
22     for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
23     return fa[x][0];
24 }
25 int update(int &d,int l,int r,int x,int y)
26 {
27     if (!d) d=++cnt;
28     if (l==r) { t[d].sum+=y,t[d].v=l; return 0; }
29     int mid=l+r>>1;
30     if (x<=mid) update(t[d].l,l,mid,x,y); else update(t[d].r,mid+1,r,x,y);
31     pushup(d);
32 }
33 int merge(int x,int y,int l,int r)
34 {
35     if (!x) return y;
36     if (!y) return x;
37     if (l==r) { t[x].sum+=t[y].sum,t[x].v=l; return x; }
38     int mid=l+r>>1;
39     t[x].l=merge(t[x].l,t[y].l,l,mid),t[x].r=merge(t[x].r,t[y].r,mid+1,r);
40     pushup(x); return x;
41 }
42 void dfs1(int x,int pre)
43 {
44     for (int i=0;i<e[x].size();i++) if (e[x][i]!=pre) dfs1(e[x][i],x),merge(root[x],root[e[x][i]],1,N-10);
45     for (int i=0;i<p[x].size();i++) update(root[x],1,N-10,p[x][i],1);
46     for (int i=0;i<q[x].size();i++) update(root[x],1,N-10,q[x][i],-1);
47     ans[x]=t[root[x]].v;
48 }
49 int main()
50 {
51     scanf("%d%d",&n,&m);
52     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),e[x].push_back(y),e[y].push_back(x);
53     dfs(1,0,1);
54     for (int i=1,x,y,z;i<=m;i++)
55     {
56         scanf("%d%d%d",&x,&y,&z);
57         int lca=LCA(x,y);
58         p[x].push_back(z),p[y].push_back(z),q[lca].push_back(z);
59         if (fa[lca][0]) q[fa[lca][0]].push_back(z); 
60     }
61     dfs1(1,0);
62     for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
63 }

 

posted @ 2019-07-12 15:15 BEYang_Z 阅读(...) 评论(...) 编辑 收藏