zoukankan      html  css  js  c++  java
  • 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)

    题目背景

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

    题目描述

    首先村落里的一共有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: 复制
    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%的数据,1 <= n, m <= 100
    对于50%的数据,1 <= n, m <= 2000
    对于100%的数据,1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000
    Vani

    题解:这题的话主要是差分的思想,把每条覆盖路径离线下来,分解成(u,lca(u,v))(u,lca(u,v))(u,lca(u,v)),(v,lca(u,v))(v,lca(u,v))(v,lca(u,v))两条路径,在uuu点和vvv点将zzz位置+1+1+1,在lca(u,v)lca(u,v)lca(u,v)和fa(lca(u,v))fa(lca(u,v))fa(lca(u,v))的位置分别−1-1−1就可以了。每个点直接查询最大值,即为答案。

    代码如下:

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lson tr[now].l
    #define rson tr[now].r
    using namespace std;
    
    struct tree
    {
        int l,r,sum,val;
    }tr[5000050];
    
    int n,m,deep[100010],a[100010],cnt,rt[100010],fa[100010][18],ans[100010];
    vector<int> g[100010];
    vector<int> op1[100010],op2[100010];
    
    int dfs(int now,int f,int dep)
    {
        fa[now][0]=f;
        deep[now]=dep;
        rt[now]=now;
        cnt++;
        for(int i=1;i<=17;i++)
        {
            fa[now][i]=fa[fa[now][i-1]][i-1];
        }
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i]==f) continue;
            dfs(g[now][i],now,dep+1);
        }
    }
    
    int lca(int x,int y)
    {
        if(deep[x]<deep[y]) swap(x,y);
        for(int i=17;i>=0;i--) if(deep[fa[x][i]]>=deep[y]) x=fa[x][i];
        if(x==y) return y;
        for(int i=17;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int push_up(int now)
    {
        if(tr[rson].sum>tr[lson].sum)
        {
            tr[now].sum=tr[rson].sum;
            tr[now].val=tr[rson].val;
        }
        else
        {
            tr[now].sum=tr[lson].sum;
            tr[now].val=tr[lson].val;
        }
    }
    
    int update(int &now,int l,int r,int pos,int v)
    {
        if(!now) now=++cnt;
        if(l==r)
        {
            tr[now].sum+=v;
            tr[now].val=l;
            return 0;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) update(lson,l,mid,pos,v);
        else update(rson,mid+1,r,pos,v);
        push_up(now);
    }
    
    int merge(int now,int a,int l,int r)
    {
        if(!now) return a;
        if(!a) return now;
        if(l==r)
        {
            tr[now].sum+=tr[a].sum;
            tr[now].val=l;
            return now;
        }
        int mid=(l+r)>>1;
        lson=merge(lson,tr[a].l,l,mid);
        rson=merge(rson,tr[a].r,mid+1,r);
        push_up(now);
        return now;
    }
    
    int dfs2(int now,int f)
    {
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i]==f) continue;
            dfs2(g[now][i],now);
            merge(rt[now],rt[g[now][i]],1,100000);
        }
        for(int i=0;i<op1[now].size();i++)
        {
            update(rt[now],1,100000,op1[now][i],1);
        }
        for(int i=0;i<op2[now].size();i++)
        {
            update(rt[now],1,100000,op2[now][i],-1);
        }
        ans[now]=tr[rt[now]].val;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        int from,to,cost;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&from,&to);
            g[from].push_back(to);
            g[to].push_back(from);
        }
        dfs(1,0,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&from,&to,&cost);
            int ttt=lca(from,to);
            op1[from].push_back(cost);
            op1[to].push_back(cost);
            op2[ttt].push_back(cost);
            if(fa[ttt][0]) op2[fa[ttt][0]].push_back(cost);
        }
        dfs2(1,0);
        for(int i=1;i<=n;i++)
        {
            printf("%d
    ",ans[i]);
        }
    }

    这题的话主要是差分的思想,把每条覆盖路径离线下来,分解成(u,lca(u,v))(u,lca(u,v))(u,lca(u,v)),(v,lca(u,v))(v,lca(u,v))(v,lca(u,v))两条路径,在uuu点和vvv点将zzz位置+1+1+1,在lca(u,v)lca(u,v)lca(u,v)fa(lca(u,v))fa(lca(u,v))fa(lca(u,v))的位置分别−1-11就可以了。每个点直接查询最大值,即为答案。

  • 相关阅读:
    web前端之Javascript的输出
    python编码问题
    python面试题1
    机器学习三剑客补充
    JavaScript设计模式与开发实践 组合模式
    JavaScript设计模式与开发实践 命令模式
    JavaScript设计模式与开发实践 发布—订阅模式
    JavaScript设计模式与开发实践 迭代器模式
    JavaScript设计模式与开发实践 代理模式
    JavaScript设计模式与开发实践 策略模式
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9661878.html
Copyright © 2011-2022 走看看