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

[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;
}








https://www.luogu.com.cn/problem/P3224







posted @ 2024-12-19 19:35  Glowingfire  阅读(28)  评论(0)    收藏  举报