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





    这道题看到了树上路径的操作,很容易就想到了树剖,可是这个题中,每一个树上的节点下面都有klogk个节点,树剖的链上操作并不能快速的修改每个点内的每种颜色的权值线段树,所以说树剖就解决不了这个问题,

    这其实就可以用差分来解决这个问题,一看到链上操作,最后统计答案,自然而然的想到树上差分

    ,a++ ,b++,lca--,fa[lca]--就可以完成一条链的操作。

    一开始可以想,我们每个节点上开一个cnt数组表示i这个数字出现了多少次,那么节点i上出现最多的数字就是cnt数组的最大值

    那么我们求i节点的cnt数组可以暴力的把它的所有孩子的cnt数组按位相加起来来进行求解,然后如果这个节点上有插入或者删除数字的操作我们再对cnt数组进行几次操作就行了~

    不过这样太慢了……发现这个东西慢主要是数组按位相加这个操作,所以我们可以用线段树合并来实现数组按位相加这个操作

    复杂度o(能过)

    不会证明,玄学的复杂度,说是o(nlogn+n)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define N 100002
     5 using namespace std;
     6 int p[N][21],head[N],tot,deep[N],tr[N*50],A[N*50],L[N*50],R[N*50],num[N],rt[N],top,ans[N],toy;
     7 struct zzh{
     8   int n,to;
     9 }e[N<<1];
    10 struct bi{
    11     int a,b,d;
    12 }q[N];
    13 inline void add(int u,int v){
    14     e[++tot].n=head[u];
    15     e[tot].to=v;
    16     head[u]=tot;
    17 }
    18 void dfs(int u,int fa){
    19     for(int i=1;(1<<i)<=deep[u];++i)p[u][i]=p[p[u][i-1]][i-1];
    20     for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
    21         int v=e[i].to;p[v][0]=u;deep[v]=deep[u]+1;
    22         dfs(v,u);
    23     }
    24 }
    25 inline int getlca(int a,int b){
    26     if(deep[a]<deep[b])swap(a,b);
    27     int k=deep[a]-deep[b];
    28     for(int i=20;i>=0;--i)if(k>=(1<<i))a=p[a][i],k-=(1<<i);
    29     if(a==b)return a;
    30     for(int i=20;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
    31     return p[a][0];
    32 }
    33 void upd(int &cnt,int l,int r,int x,int y){
    34     if(!cnt)cnt=++toy;
    35     if(l==r){
    36         tr[cnt]+=y;
    37         if(tr[cnt]>0)A[cnt]=num[l];
    38         else A[cnt]=0;
    39         return;
    40     }
    41     int mid=(l+r)>>1;
    42     if(mid>=x)upd(L[cnt],l,mid,x,y);
    43     else upd(R[cnt],mid+1,r,x,y);
    44     tr[cnt]=max(tr[L[cnt]],tr[R[cnt]]);
    45     if(tr[L[cnt]]>=tr[R[cnt]])A[cnt]=A[L[cnt]];
    46     else A[cnt]=A[R[cnt]];
    47 }
    48 int query(int &cnt,int l,int r){
    49     if(!cnt)return 0;// 这个意思是这个点根本就没开,当然返回0了,我把这句删了就T了,为啥呢??
    50     return A[cnt];
    51     if(l==r)return num[l];
    52     int mid=(l+r)>>1;
    53     if(tr[L[cnt]]>=tr[R[cnt]])return query(L[cnt],l,mid);
    54     else return query(R[cnt],mid+1,r);
    55 }
    56 int merge(int &u,int v,int l,int r){
    57     if(!u||!v)return u+v;
    58     if(l==r){
    59         tr[u]+=tr[v];
    60         if(tr[u])A[u]=num[l];
    61         else A[u]=0;
    62         return u;
    63     }
    64     int mid=(l+r)>>1;
    65     L[u]=merge(L[u],L[v],l,mid);
    66     R[u]=merge(R[u],R[v],mid+1,r);
    67     tr[u]=max(tr[L[u]],tr[R[u]]);
    68      if(tr[L[u]]>=tr[R[u]])A[u]=A[L[u]];
    69     else A[u]=A[R[u]];
    70     return u;
    71 }
    72 void dfs2(int u,int fa){
    73     for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
    74         int v=e[i].to;
    75         dfs2(v,u);
    76         rt[u]=merge(rt[u],rt[v],1,top);
    77     }
    78     ans[u]=query(rt[u],1,top);
    79 }
    80 int main(){
    81    int n,m,u,v;
    82     scanf("%d%d",&n,&m);
    83     for(int i=1;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
    84     dfs(1,0);
    85     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;
    86     sort(num+1,num+top+1);
    87     top=unique(num+1,num+top+1)-num-1;
    88     for(int i=1;i<=m;++i){
    89         q[i].d=lower_bound(num+1,num+top+1,q[i].d)-num;
    90         int lca=getlca(q[i].a,q[i].b);
    91         upd(rt[q[i].a],1,top,q[i].d,1);upd(rt[q[i].b],1,top,q[i].d,1);
    92         upd(rt[lca],1,top,q[i].d,-1);upd(rt[p[lca][0]],1,top,q[i].d,-1);
    93     }
    94     dfs2(1,0);
    95     for(int i=1;i<=n;++i)printf("%d
    ",ans[i]);
    96     return 0;
    97 }




  • 相关阅读:
    Linux中查找当前目录下占用空间最大的前10个文件
    Redis的优势和特点
    java中final,finally,finalize三个关键字的区别
    消息队列介绍
    Redis的应用场景
    Spring中@Autowired注解与@Resource注解的区别
    多版本并发控制(MVCC)
    Linux查看CPU和内存使用情况
    进程调度算法
    一致性Hash算法
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10596045.html
Copyright © 2011-2022 走看看