zoukankan      html  css  js  c++  java
  • bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)

    Description

    N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
    对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
    所有发放后,每个点存放最多的是哪种物品。

    Input

    第一行数字N,M
    接下来N-1行,每行两个数字a,b,表示a与b间有一条边
    再接下来M行,每行三个数字x,y,z.如题

    Output

    输出有N行
    每i行的数字表示第i个点存放最多的物品是哪一种,如果有
    多种物品的数量一样,输出编号最小的。如果某个点没有物品
    则输出0

    看到对树上路径进行操作,(以蒟蒻博主目前的知识水平)无非两个选择,树剖/树上差分

    但是最后只询问一次的话差分会是更好的选择

    而且我们要进行的操作并非只是对点的权值进行更改,而是对于每个点插入新的权值并统计出众数

    这时候应该想到在每一个节点建权值线段树来维护信息

    这样差分的操作就利用权值线段树的插入操作解决了

    然鹅在最后统计的时候要合并子树信息

    所以还需要线段树合并

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=100005;
    int n,m,to[N<<1],nxt[N<<1],head[N],tot=0;
    int size[N*50],type,root[N],ls[N*50],rs[N*50],fa[N][22],dep[N],now[N*50],ans[N];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')
        {if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')
        {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    void dfs(int x,int deep)
    {
        dep[x]=deep;
        for(int i=1;i<=20;i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=head[x];i;i=nxt[i])
        {
            if(dep[to[i]])continue;
            fa[to[i]][0]=x;
            dfs(to[i],deep+1);
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y])swap(x,y);
        for(int i=20;i>=0;i--)
            if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
        if(x==y)return x;
        for(int i=20;i>=0;i--)
            if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    void up(int x)
    {
        if(size[ls[x]]>=size[rs[x]])
        {
            size[x]=size[ls[x]];
            now[x]=now[ls[x]];
        }
        else 
        {
            size[x]=size[rs[x]];
            now[x]=now[rs[x]];
        }
    }
    void update(int &k,int l,int r,int val,int num)
    {
        if(!k)k=++type;
        if(l==r)
        {
            size[k]+=num;
            now[k]=l;
            return ;
        }
        int mid=l+r>>1;
        if(val<=mid)update(ls[k],l,mid,val,num);
        else update(rs[k],mid+1,r,val,num);
        up(k);
        return ;
    }
    int Merge(int x,int y,int l,int r)
    {
        if(!x||!y)return x+y;
        if(l==r)
        {
            size[x]=size[x]+size[y];
            now[x]=l; 
            return x;
        }
        int mid=l+r>>1;
        ls[x]=Merge(ls[x],ls[y],l,mid);
        rs[x]=Merge(rs[x],rs[y],mid+1,r);
        up(x);
        return x;
    }
    void cacl(int x)
    {
        for(int i=head[x];i;i=nxt[i])
        {
            if(to[i]==fa[x][0])continue;
            cacl(to[i]);
            root[x]=Merge(root[x],root[to[i]],1,N-5);
        }
        if(now[root[x]])ans[x]=now[root[x]];
        else ans[x]=0;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        dfs(1,1);
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read();
            int LCA=lca(x,y);//cout<<"///"<<LCA<<endl;
            update(root[x],1,N-5,z,1);
            update(root[y],1,N-5,z,1);
            update(root[LCA],1,N-5,z,-1);
            update(root[fa[LCA][0]],1,N-5,z,-1);
        }
        cacl(1);
        for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
        return 0;
    } 
     
  • 相关阅读:
    caffe解析
    分布式内存文件系统Tachyon
    用友微服务事务一致性实践
    这样的单点登录才最有效果,很多大咖牛人都不知道!
    基于开发者中心DevOps流水线快速上云
    用友云服务治理平台 助力企业微服务架构落地
    玩事业务中台构建之路
    数字澳洋背后的用友云混合云架构支撑
    企业互联网应用高性能解决之道
    iUAP云运维平台v3.0全面支持基于K8s的微服务架构
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11032252.html
Copyright © 2011-2022 走看看