zoukankan      html  css  js  c++  java
  • P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并

    P4556 [Vani有约会]雨天的尾巴

    提交2.75k
    通过789
    时间限制1.00s
    内存限制125.00MB
    题目提供者yyy2015c01
    历史分数100
     提交记录  查看题解

    标签

     
     查看算法标签

    相关讨论

    进入讨论版
     查看讨论

    推荐题目

     查看推荐
     展开

    题目背景

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

    题目描述

    首先村落里的一共有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

    这题很明显是一道树剖题 但是可以用线段树合并来解决  

    显然每个点维护一个权值线段树  可以直接输出做多的粮食是什么 

    因为线段树合并自下而上类似一个求前缀和的过程 所以可以利用差分数组 点更新

    在u+1 v+1 lca(u,v)-1 falca(u,v)-1  即可

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=6000005;
    
    int T[N<<2],lson[N<<2],rson[N<<2],maxx[N<<2],t[N<<2],ncnt,n,m,nn,ans[N];
    void up(int pos)
    {
        if(maxx[lson[pos]]>=maxx[rson[pos]])
        maxx[pos]=maxx[lson[pos]],t[pos]=t[lson[pos]];
        else maxx[pos]=maxx[rson[pos]],t[pos]=t[rson[pos]];
    }
    void upnode(int x,int v,int l,int r,int &pos)
    {
        if(!pos)pos=++ncnt;
        if(l==r){t[pos]=l;maxx[pos]+=v;return ;}
        int m=(l+r)>>1;
        if(x<=m)upnode(x,v,l,m,lson[pos]);
        else upnode(x,v,m+1,r,rson[pos]);
        up(pos);
    }
    int Merge(int a,int b,int l,int r)
    {
        if(!a)return b;
        if(!b)return a;
        if(l==r)
        {
            maxx[a]+=maxx[b];
            t[a]=l;
            return a;
        }
        int m=(l+r)>>1;
        lson[a]=Merge(lson[a],lson[b],l,m);
        rson[a]=Merge(rson[a],rson[b],m+1,r);
        up(a);
        return a;
    }
    ////////////////////////
    int fa[N],top[N],siz[N],son[N],dep[N],pos,head[N];
    struct Edge{int to,nex;}edge[N];
    void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
    
    void dfs1(int x,int f)
    {
        fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0;
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;if(v==f)continue;
            dfs1(v,x);siz[x]+=siz[v];
            if(siz[son[x]]<siz[v])son[x]=v;
        }
    }
    void dfs2(int x,int topf)
    {
        top[x]=topf;
        if(son[x])dfs2(son[x],topf);
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;if(v==fa[x]||v==son[x])continue;
            dfs2(v,v);
        }
    }
    int Lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        return dep[x]<dep[y]?x:y;
    }
    void dfs3(int x)
    {
        for(int i=head[x];i;i=edge[i].nex)if(dep[edge[i].to]>dep[x])
        dfs3(edge[i].to),T[x]=Merge(T[x],T[edge[i].to],1,nn);
        if(maxx[T[x]])ans[x]=t[T[x]];
    }
    int L[N],R[N],V[N];
    int main()
    {
        cin>>n>>m;
        rep(i,1,n-1)
        {
            int x,y;scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        rep(i,1,n)T[i]=i,++ncnt;
        dfs1(1,0);
        dfs2(1,1);
        rep(i,1,m)
        {
            scanf("%d%d%d",&L[i],&R[i],&V[i]);
            nn=max(nn,V[i]);
        }
        rep(i,1,m)
        {
            int lca=Lca(L[i],R[i]);
            upnode(V[i],1,1,nn,T[L[i]]);
            upnode(V[i],1,1,nn,T[R[i]]);
            upnode(V[i],-1,1,nn,T[lca]);
            if(fa[lca])upnode(V[i],-1,1,nn,T[fa[lca]]);
        }
        dfs3(1);
        rep(i,1,n)
        printf("%d
    ",ans[i]);
    
        return 0;
    }
    View Code

    也可以用树链剖分差分来做

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=1e5+100;
    int maxx[N<<2],t[N<<2],pos,head[N],ans[N],n,m,a,b,c,pre[N];
    vector<int>table[N];
    void up(int pos)
    {
        if(maxx[pos<<1]>=maxx[pos<<1|1])
        maxx[pos]=maxx[pos<<1],t[pos]=t[pos<<1];
        else maxx[pos]=maxx[pos<<1|1],t[pos]=t[pos<<1|1];
    }
    void build(int l,int r,int pos)
    {
        if(l==r){maxx[pos]=0;t[pos]=l;return;}
        int m=(l+r)>>1;
        build(l,m,pos<<1);build(m+1,r,pos<<1|1);
        up(pos);
    }
    void upnode(int x,int v,int l,int r,int pos)
    {
        if(l==r){maxx[pos]+=v;return ;}
        int m=(l+r)>>1;
        if(x<=m)upnode(x,v,l,m,pos<<1);
        else upnode(x,v,m+1,r,pos<<1|1);
        up(pos);
    }
    int son[N],siz[N],fa[N],top[N],id[N],ncnt,dep[N];
    struct Edge{int to,nex;}edge[N<<1];
    void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
    void dfs1(int x,int f)
    {
        fa[x]=f;dep[x]=dep[f]+1;son[x]=0;siz[x]=1;
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;if(v==f)continue;
            dfs1(v,x);siz[x]+=siz[v];
            if(siz[son[x]]<siz[v])son[x]=v;
        }
    }
    void dfs2(int x,int topf)
    {
        top[x]=topf;id[x]=++ncnt;pre[ncnt]=x;
        if(son[x])dfs2(son[x],topf);
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;if(v==son[x]||v==fa[x])continue;
            dfs2(v,v);
        }
    }
    void UPsum(int x,int y,int v)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            table[id[top[x]]].push_back(v);table[id[x]+1].push_back(-v);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        table[id[x]].push_back(v);table[id[y]+1].push_back(-v);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        rep(i,1,n-1)
        {
            scanf("%d%d",&a,&b);add(a,b);add(b,a);
        }
        dfs1(1,1);
        dfs2(1,1);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            UPsum(a,b,c);
        }
        build(1,1e5,1);
        rep(i,1,n)
        {
            for(auto v:table[i])
            if(v>0)upnode(v,1,1,1e5,1);
            else upnode(-v,-1,1,1e5,1);
            if(maxx[1])
            ans[pre[i]]=t[1];
            else ans[pre[i]]=0;
        }
        rep(i,1,n)printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
     
     
     
     
     
     
  • 相关阅读:
    Java实现 LeetCode 413 等差数列划分
    Java实现 LeetCode 413 等差数列划分
    Java实现 LeetCode 412 Fizz Buzz
    简单字符设备驱动程序
    fork与vfork的区别
    进程创建函数fork()、vfork() ,以及excel()函数
    区分execl与system——应用程序中执行命令
    CMOS Sensor的调试经验分享
    嵌入式ARM-Linux开发工具下载地址合集
    嵌入式 linux 查看内存
  • 原文地址:https://www.cnblogs.com/bxd123/p/11383715.html
Copyright © 2011-2022 走看看