[Vani有约会] 雨天的尾巴 /【模板】线段树合并
题目背景
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
题目描述
首先村落里的一共有 \(n\) 座房屋,并形成一个树状结构。然后救济粮分 \(m\) 次发放,每次选择两个房屋 \((x, y)\),然后对于 \(x\) 到 \(y\) 的路径上(含 \(x\) 和 \(y\))每座房子里发放一袋 \(z\) 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
输入格式
输入的第一行是两个用空格隔开的正整数,分别代表房屋的个数 \(n\) 和救济粮发放的次数 \(m\)。
第 \(2\) 到 第 \(n\) 行,每行有两个用空格隔开的整数 \(a, b\),代表存在一条连接房屋 \(a\) 和 \(b\) 的边。
第 \((n + 1)\) 到第 \((n + m)\) 行,每行有三个用空格隔开的整数 \(x, y, z\),代表一次救济粮的发放是从 \(x\) 到 \(y\) 路径上的每栋房子发放了一袋 \(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, m \leq 100\)。
- 对于 \(50\%\) 的数据,保证 \(n, m \leq 2 \times 10^3\)。
- 对于 \(100\%\) 测试数据,保证 \(1 \leq n, m \leq 10^5\),\(1 \leq a,b,x,y \leq n\),\(1 \leq z \leq 10^5\)。
#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;
}
标签:lc,int,P4556,leq,num,rc,Vani,救济粮,模板
From: https://www.cnblogs.com/Glowingfire/p/18617814