权值线段树-动态开点-合并(P4556 [Vani有约会]雨天的尾巴
Posted --hpy-7m
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权值线段树-动态开点-合并(P4556 [Vani有约会]雨天的尾巴相关的知识,希望对你有一定的参考价值。
题意:https://www.luogu.com.cn/problem/P4556
树链加数,问你每个节点最多的是哪个数。
思路:
树链加数很容易想到差分。
从下往上用权值线段树合并即可,直接用pushup把答案存在树根即可,不用每次查询最多的数
1 struct EDGE 2 { 3 int to,next; 4 }edge[N]; 5 int tot; 6 int head[N]; 7 void Init(int n) 8 { 9 tot=0; 10 for(int i=0;i<=n;++i) 11 head[i]=0; 12 } 13 void add(int from,int to) 14 { 15 ++tot; 16 edge[tot].to=to; 17 edge[tot].next=head[from]; 18 head[from]=tot; 19 }//for(int i=head[x];i;i=edge[i].next) 20 21 int f[N][25],d[N]; 22 void update(int x) {//用之前记得设f[x][0] 23 for (int i=1; i<=24; i++) 24 f[x][i]=f[f[x][i-1]][i-1]; 25 return ; 26 } 27 int LCA(int a, int b) { 28 if (d[a]>d[b]) swap(a, b); 29 int h=d[b]-d[a]; 30 for (int i=0; (1<<i)<=h; i++) 31 if ((1<<i)&h) b=f[b][i]; 32 if (a!=b) { 33 for (int i=24; i>=0; i--) 34 if (f[a][i]!=f[b][i]) a=f[a][i], b=f[b][i]; 35 a=f[a][0]; 36 } 37 return a; 38 } 39 void dfs1(int u,int fa){ 40 f[u][0]=fa; 41 d[u]=d[fa]+1; 42 update(u); 43 for(int i=head[u];i;i=edge[i].next) 44 { 45 int to=edge[i].to; 46 if(to==fa)continue; 47 dfs1(to,u); 48 } 49 } 50 51 int top; 52 struct node 53 { 54 int sz,ans,lson,rson; 55 }tr[N]; 56 int rt[N],R=100005; 57 int res[N]; 58 void up(int x){ 59 if(tr[tr[x].lson].sz>=tr[tr[x].rson].sz)tr[x].ans=tr[tr[x].lson].ans,tr[x].sz=tr[tr[x].lson].sz; 60 else tr[x].ans=tr[tr[x].rson].ans,tr[x].sz=tr[tr[x].rson].sz; 61 } 62 void insert(int &x,int l,int r,int pos,int val) 63 { 64 if(!x)x=++top,tr[top]=node(); 65 if(l==r){ 66 tr[x].sz+=val; 67 tr[x].ans=l; 68 return; 69 } 70 int mid=l+r>>1; 71 if(pos<=mid)insert(tr[x].lson,l,mid,pos,val); 72 else insert(tr[x].rson,mid+1,r,pos,val); 73 up(x); 74 } 75 int n,m; 76 int merge(int x,int y,int l,int r) 77 { 78 if(!x||!y)return x+y; 79 if(l==r){ 80 tr[x].sz+=tr[y].sz; 81 return x; 82 } 83 int mid=l+r>>1; 84 tr[x].lson=merge(tr[x].lson,tr[y].lson,l,mid); 85 tr[x].rson=merge(tr[x].rson,tr[y].rson,mid+1,r); 86 up(x); 87 return x; 88 } 89 void dfs(int u,int fa) 90 { 91 for(int i=head[u];i;i=edge[i].next) 92 { 93 int to=edge[i].to; 94 if(to==fa)continue; 95 dfs(to,u); 96 rt[u]=merge(rt[u],rt[to],1,R); 97 } 98 if(tr[u].sz)res[u]=tr[rt[u]].ans; 99 } 100 101 signed main() 102 { 103 sc("%d%d",&n,&m); 104 for(int i=1;i<n;++i) 105 { 106 int u,v; 107 sc("%d%d",&u,&v); 108 add(u,v); 109 add(v,u); 110 } 111 dfs1(1,0); 112 top=0; 113 for(int i=1;i<=n;++i)rt[i]=++top; 114 for(int i=1;i<=m;++i) 115 { 116 int u,v,val; 117 sc("%d%d%d",&u,&v,&val); 118 int lca=LCA(u,v); 119 insert(rt[u],1,R,val,1); 120 insert(rt[v],1,R,val,1); 121 insert(rt[lca],1,R,val,-1); 122 if(f[lca][0]) 123 insert(rt[f[lca][0]],1,R,val,-1); 124 } 125 dfs(1,0); 126 for(int i=1;i<=n;++i) 127 pr("%d ",res[i]); 128 return 0; 129 }
以上是关于权值线段树-动态开点-合并(P4556 [Vani有约会]雨天的尾巴的主要内容,如果未能解决你的问题,请参考以下文章
P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)
P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)
P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)
P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)