P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并

[Vani有约会] 雨天的尾巴 /【模板】线段树合并

题目背景

深绘里一直很讨厌雨天。

灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。

无奈的深绘里和村民们只好等待救济粮来维生。

不过救济粮的发放方式很特别。

题目描述

首先村落里的一共有 n 座房屋,并形成一个树状结构。然后救济粮分 m 次发放,每次选择两个房屋 (x,y),然后对于 xy 的路径上(含 xy)每座房子里发放一袋 z 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

输入格式

输入的第一行是两个用空格隔开的正整数,分别代表房屋的个数 n 和救济粮发放的次数 m

2 到 第 n 行,每行有两个用空格隔开的整数 a,b,代表存在一条连接房屋 ab 的边。

(n+1) 到第 (n+m) 行,每行有三个用空格隔开的整数 x,y,z,代表一次救济粮的发放是从 xy 路径上的每栋房子发放了一袋 z 类型的救济粮。

输出格式

输出 n 行,每行一个整数,第 i 行的整数代表 i 号房屋存放最多的救济粮的种类,如果有多种救济粮都是存放最多的,输出种类编号最小的一种。

如果某座房屋没有救济粮,则输出 0

样例 #1

样例输入 #1

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

样例输出 #1

2
3
3
0
2

提示

  • 对于 20% 的数据,保证 n,m100
  • 对于 50% 的数据,保证 n,m2×103
  • 对于 100% 测试数据,保证 1n,m1051a,b,x,yn1z105
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+100,INF=1e5;
struct segtree
{
int val,lc,rc,num;
}s[N<<7];
vector<int >to[N];
int n,m,root[N],deg[N],tot,ans[N];
int dep[N],f[N],siz[N],son[N],top[N];
void go1(int u,int fa)
{
f[u]=fa;
siz[u]=1;
dep[u]=dep[fa]+1;
for(int i=0;i<deg[u];++i)
{
int v=to[u][i];
if(v==fa)
continue;
go1(v,u);
siz[u]+=siz[v];
if(siz [ son[u] ] < siz[v])
son[u]=v;
}
}
void go2(int u,int tp)
{
top[u]=tp;
if(son[u])
go2(son[u],tp);
for(int i=0;i<deg[u];++i)
{
int v=to[u][i];
if(v==son[u] || dep[v]<dep[u])
continue;
go2(v,v);
}
}
int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]] < dep[top[y]])
swap(x,y);
x=f[top[x]];
}
if(dep[x]<dep[y])
swap(x,y);
return y;
}
void pushup(segtree &nw,segtree &lc,segtree &rc)
{
nw.val=lc.val+rc.val;
nw.num=max(lc.num,rc.num);
}
void upd(int &i,int l,int r,int x,int z)
{
if(i==0)
i=++tot;
if(l==r)
{
s[i].val+=z;
s[i].num=s[i].val;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)
upd(s[i].lc,l,mid,x,z);
else
upd(s[i].rc,mid+1,r,x,z);
pushup(s[i],s[s[i].lc],s[s[i].rc]);
}
int que(int i,int l,int r)
{
if(l==r)
return l;
int mid=(l+r)>>1,num=0;
if(s[ s[i].lc ].num>=s[ s[i].rc ].num)
num=que(s[i].lc,l,mid);
else
num=que(s[i].rc,mid+1,r);
return num;
}
void merg(int &i,int &j,int l,int r)//i <-- j
{
if(i==0 || j==0)
{
i+=j;
return ;
}
if(l==r)
{
s[i].val+=s[j].val;
s[i].num=s[i].val;
return ;
}
int mid=(l+r)>>1;
merg(s[i].lc,s[j].lc,l,mid);
merg(s[i].rc,s[j].rc,mid+1,r);
pushup(s[i], s[s[i].lc] , s[s[i].rc]);
}
void gotans(int u);
void init()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<n;++i)
{
scanf("%d%d",&x,&y);
++deg[x];
++deg[y];
to[x].push_back(y);
to[y].push_back(x);
}
go1(1,0);
go2(1,1);
}
void work()
{
for(int i=1,x,y,z;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&z);
int ace=lca(x,y);
upd(root[x],1,INF,z,1);
upd(root[y],1,INF,z,1);
upd(root[ace],1,INF,z,-1);
if(f[ace]>0)
upd(root[f[ace]],1,INF,z,-1);
}
gotans(1);
for(int i=1;i<=n;++i)
printf("%d\n",ans[i]);
}
void gotans(int u)
{
for(int i=0,v;i<deg[u];++i)
{
v=to[u][i];
if(dep[v]<dep[u])
continue;
gotans(v);
merg(root[u],root[v],1,INF);
}
if(root[u]>0)
ans[u]=que(root[u],1,INF);
}
int main()
{
init();
work();
return 0;
}
https://www.luogu.com.cn/problem/P3224
posted @   Glowingfire  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示