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

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

    Solution

    一看到链上操作,最后统计答案,自然而然的想到树上差分,a++ ,b++,lca--,fa[lca]--就可以完成一条链的操作。

    但这道题加的东西有好多种类。

    所以考虑对每个节点开一颗线段树,每次在对应位置加上。

    然后我们DFS的时候,朴素的树上差分直接size[u]+=size[v] (son[u]==v)这回u和v是两颗线段树。

    所以用线段数合并就行了。

    由于这题涉及大量的线段树,所以我们的数组得开大点。

    颜色需要提前离散化。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 100002
    using namespace std;
    int p[N][21],head[N],tot,deep[N],tr[N*50],L[N*50],R[N*50],num[N],rt[N],top,ans[N],toy;
    struct zzh{
      int n,to;
    }e[N<<1];
    struct bi{
        int a,b,d;
    }q[N];
    inline void add(int u,int v){
        e[++tot].n=head[u];
        e[tot].to=v;
        head[u]=tot;
    }
    void dfs(int u,int fa){
        for(int i=1;(1<<i)<=deep[u];++i)p[u][i]=p[p[u][i-1]][i-1];
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
            int v=e[i].to;p[v][0]=u;deep[v]=deep[u]+1;
            dfs(v,u);
        }
    }
    inline int getlca(int a,int b){
        if(deep[a]<deep[b])swap(a,b);
        for(int i=20;i>=0;--i)if(deep[a]-(1<<i)>=deep[b])a=p[a][i];
        if(a==b)return a;
        for(int i=20;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
        return p[a][0];
    }
    void upd(int &cnt,int l,int r,int x,int y){
        if(!cnt)cnt=++toy;
        if(l==r){
            tr[cnt]+=y;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x)upd(L[cnt],l,mid,x,y);
        else upd(R[cnt],mid+1,r,x,y);
        tr[cnt]=max(tr[L[cnt]],tr[R[cnt]]);
    }
    int query(int &cnt,int l,int r){    
        if(!tr[cnt]||!cnt)return 0;
        if(l==r)return num[l];
        int mid=(l+r)>>1;
        if(tr[L[cnt]]>=tr[R[cnt]])return query(L[cnt],l,mid);
        else return query(R[cnt],mid+1,r);
    }
    int merge(int &u,int v,int l,int r){
        if(!u||!v)return u+v;
        if(l==r){
            tr[u]+=tr[v];
            return u;
        }
        int mid=(l+r)>>1;
        L[u]=merge(L[u],L[v],l,mid);
        R[u]=merge(R[u],R[v],mid+1,r);
        tr[u]=max(tr[L[u]],tr[R[u]]);
        return u;
    }
    void dfs2(int u,int fa){
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
            int v=e[i].to;
            dfs2(v,u);
            rt[u]=merge(rt[u],rt[v],1,top);
        }
        ans[u]=query(rt[u],1,top);
    }
    int main(){
       int n,m,u,v;
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
        dfs(1,0);
        for(int i=1;i<=m;++i)scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].d),num[++top]=q[i].d;
        sort(num+1,num+top+1);
        top=unique(num+1,num+top+1)-num-1;
        for(int i=1;i<=m;++i){
            q[i].d=lower_bound(num+1,num+top+1,q[i].d)-num;
            int lca=getlca(q[i].a,q[i].b);
            upd(rt[q[i].a],1,top,q[i].d,1);upd(rt[q[i].b],1,top,q[i].d,1);
            upd(rt[lca],1,top,q[i].d,-1);upd(rt[p[lca][0]],1,top,q[i].d,-1);
        }
        dfs2(1,0);
        for(int i=1;i<=n;++i)printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9668780.html
Copyright © 2011-2022 走看看