luogu4556 雨天的尾巴 (线段树合并+差分)

题目背景

深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
题目描述

首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
输入输出格式
输入格式:

第一行两个正整数n,m,含义如题目所示。
接下来n-1行,每行两个数(a,b),表示(a,b)间有一条边。
再接下来m行,每行三个数(x,y,z),含义如题目所示。

输出格式:

n行,第i行一个整数,表示第i座房屋里存放的最多的是哪种救济粮,如果有多种救济粮存放次数一样,输出编号最小的。
如果某座房屋里没有救济粮,则对应一行输出0。

-------------------------------------------------华丽的分割线-----------------------------------------------

对于每一个节点都建一颗权值线段树(只建有用的部分)来存该节点的信息

暴力建的话显然在时间上不允许。。。

所以用差分来解决

起点和终点重点对祖先们的贡献是1

他们的lca和lca的父节点对祖先们的贡献是-1

最后统计答案时用每个点的子节点通过合并线段树的方式更新该节点的信息。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,cnt,tot,maxn;
int pr[100005];
int ans[100005];
int head[100005];
int rt[100005];
int fa[100005];
int dep[100005];
int siz[100005];
int son[100005];
int grand[100005];
struct node{
    int u;
    int v;
    int z;
    int zx;
}ac[100005];
struct Tree{
    int ls;
    int rs;
    int num;
    int mx;
}tr[5500005];
struct Edge{
    int fr;
    int to;
    int nxt;
}edge[200005];
int cmp(node a,node b){
    return a.z<b.z;
}
void init(){
    memset(head,-1,sizeof(head));
}
void addedge(int f,int t){
    cnt++;
    edge[cnt].fr=f;
    edge[cnt].to=t;
    edge[cnt].nxt=head[f];
    head[f]=cnt;
}
void dfs1(int p){
    for(int i=head[p];i!=-1;i=edge[i].nxt){
        int e=edge[i].to;
        if(e==fa[p])continue;
        fa[e]=p;
        dep[e]=dep[p]+1;
        dfs1(e);
        siz[p]+=siz[e];
        if(siz[e]>siz[son[p]])son[p]=e;
    }
}
void dfs2(int p){
    if(p!=son[fa[p]])grand[p]=p;
    else grand[p]=grand[fa[p]];
    for(int i=head[p];i!=-1;i=edge[i].nxt){
        int e=edge[i].to;
        if(e==fa[p])continue;
        dfs2(e);
    }
}
int lca(int x,int y){
    while(grand[x]!=grand[y]){
        if(dep[grand[x]]<dep[grand[y]])swap(x,y);
        x=fa[grand[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}
void update(int o){
    if(tr[tr[o].ls].num>=tr[tr[o].rs].num){
        tr[o].num=tr[tr[o].ls].num;
        tr[o].mx=tr[tr[o].ls].mx;
    }else
    {
        tr[o].num=tr[tr[o].rs].num;
        tr[o].mx=tr[tr[o].rs].mx;
    }
}
void build(int &o,int l,int r,int p,int val){
    if(!o)o=++tot;
    if(l==r){
        tr[o].num+=val;
        if(tr[o].num)tr[o].mx=l;
        else tr[o].num=0;
        return;
    }
    int mid=(l+r)>>1;
    if(p>mid)build(tr[o].rs,mid+1,r,p,val);
    else build(tr[o].ls,l,mid,p,val);
    update(o);
}
void Merge(int &a,int b,int l,int r){
    if(!b)return;
    if(!a){
        a=b;
        return;
    }
    if(l==r){
        tr[a].num+=tr[b].num;
        tr[a].mx=l;
        return;
    }
    int mid=(l+r)>>1;
    Merge(tr[a].ls,tr[b].ls,l,mid);
    Merge(tr[a].rs,tr[b].rs,mid+1,r);
    update(a);
}
void dfs(int p){
    for(int i=head[p];i!=-1;i=edge[i].nxt){
        int e=edge[i].to;
        if(e==fa[p])continue;
        dfs(e);
        Merge(rt[p],rt[e],1,maxn);
    }
    pr[p]=tr[rt[p]].mx;
}
int main(){
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        siz[i]=1;
    }
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs1(1);
    dfs2(1);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&ac[i].u,&ac[i].v,&ac[i].z);
    }
    sort(ac+1,ac+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(ac[i].z!=ac[i-1].z)maxn++;
        ac[i].zx=maxn;
        ans[maxn]=ac[i].z;
    }
    for(int i=1;i<=m;i++){
        int f=lca(ac[i].u,ac[i].v);
        int ff=fa[f];
        build(rt[ac[i].u],1,maxn,ac[i].zx,1);
        build(rt[ac[i].v],1,maxn,ac[i].zx,1);
        build(rt[f],1,maxn,ac[i].zx,-1);
        if(ff)build(rt[ff],1,maxn,ac[i].zx,-1);
    }
    dfs(1);
    for(int i=1;i<=n;i++){
        printf("%d
",ans[pr[i]]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lnxcj/p/9588460.html