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

    题目描述

    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

     ----------------------------------van美分界线----------------------------------

    先%一发pa大佬考试A掉这题

    %%%pa

    考试时刚看到这题时觉得和之前的考试题松鼠的新家(此坑未填)很像,因为都是对树上的一条链进行修改操作

    所以很容易想到树上差分(其实树剖也可以但蒟蒻博主并不会),具体讲就是将链的两端加一,将lca和lca父亲节点减一。

    然后我们可以看到他是询问数量所以可以想到在每一个节点建一棵权值线段树来维护信息。

    又看到1e9的范围瞬间吓尿,跑去码T1,其实只要离散化一下就可以,因此我们不仅需要维护每一个节点的最大值,还要维护最大值出现的位置,这样比较方便输出答案,建立对应关系即可。

    最后dfs统计答案即可,就是从叶节点往上不断merge。

    最后要注意的一点就是和线段树有关的数组一定要开大一些,本人亲测要1e5×60,临接表数组开二倍(都这时候了我还犯这么低级错误,真沙雕)。

    回想一下这题也没那么难,但我还是断断续续调了得有5.6节课,沙雕错误百出。具体沙雕错误代码里都有注释(大佬自动忽略即可,勿喷)。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 const int N=1e5+10;
      9 int n,m;int tot;int t;
     10 int first[N],nex[N*2],to[N*2],cnt,d[N],root[N*20*3],v[N],f[N][22],sum[N*20*3],posm[N*20*3],ls[N*20*3],rs[N*20*3],ans[N],x[N],yy[N],zz[N],num[N];
     11 void add(int a,int b){
     12     to[++tot]=b;nex[tot]=first[a];first[a]=tot;
     13 }
     14 void bfs(int x){
     15     queue<int> q;
     16     q.push(x);d[x]=1;
     17     while(!q.empty()){
     18         int x=q.front();q.pop();
     19         for(int i=first[x];i;i=nex[i]){
     20             int y=to[i];
     21             if(d[y]) continue;
     22             d[y]=d[x]+1;
     23             f[y][0]=x;
     24             for(int j=1;j<=t;j++)
     25                 f[y][j]=f[f[y][j-1]][j-1];
     26             q.push(y);
     27         } 
     28     }
     29 }
     30 int Lca(int x,int y){
     31     if(d[y]<d[x]) swap(x,y);
     32     for(int i=t;i>=0;i--){
     33         if(d[f[y][i]]>=d[x]) y=f[y][i];
     34     }
     35     if(x==y) return x;
     36     for(int i=t;i>=0;i--){
     37         if(f[y][i]!=f[x][i]) x=f[x][i],y=f[y][i];
     38     }
     39     return f[x][0];
     40 }
     41 void pushup(int x){
     42     if(sum[ls[x]]>=sum[rs[x]]) sum[x]=sum[ls[x]],posm[x]=posm[ls[x]];
     43     else sum[x]=sum[rs[x]],posm[x]=posm[rs[x]];
     44 }
     45 void update(int &x,int z,int add,int l,int r){
     46     if(!x){
     47         x=++cnt;
     48     }
     49     if(l==r){
     50         sum[x]+=add;posm[x]=z/*z !l*/;
     51         return;//void  return sbsbsbsb
     52     }
     53     int mid=(l+r)>>1;
     54     if(z<=mid){
     55         update(ls[x],z,add,l,mid);//
     56     }
     57     else update(rs[x],z,add,mid+1,r);//递归儿子啊喂 
     58     pushup(x);
     59 }
     60 int merge(int x,int y,int l,int r){
     61     if(!x||!y){
     62         return x+y;
     63     }
     64     if(l==r){
     65         sum[x]+=sum[y];
     66         return x;
     67     }
     68     int mid=(l+r)>>1;
     69     ls[x]=merge(ls[x],ls[y],l,mid);
     70     rs[x]=merge(rs[x],rs[y],mid+1,r);
     71     pushup(x);
     72     return x;
     73 }
     74 void dfs(int x){
     75     for(int i=first[x];i;i=nex[i]){
     76         int y=to[i];
     77         if(y==f[x][0]) continue;
     78         //root[x]=merge(root[x],root[y],ls[x],rs[x]); my wrong way
     79         dfs(y);
     80         root[x]=merge(root[x],root[y],1,m);
     81     }
     82     if(sum[root[x]])ans[x]=num[posm[root[x]]];//num[posm[root[x]]]  x wai yaojia root
     83 }
     84 int main(){
     85     scanf("%d%d",&n,&m);
     86     t=log2(n);
     87     for(int i=1;i<n;i++){
     88         int a,b;
     89         scanf("%d%d",&a,&b);
     90         add(a,b);
     91         add(b,a);
     92     }
     93     bfs(1);
     94     for(int i=1;i<=m;i++){
     95         scanf("%d%d%d",&x[i],&yy[i],&zz[i]);
     96         num[i]=zz[i];
     97     }
     98     sort(num+1,num+1+m);
     99     for(int i=1;i<=m;i++){
    100         zz[i]=lower_bound(num+1,num+m/*m  !n*/+1,zz[i])-num;
    101         int lca=Lca(x[i],yy[i]);
    102         update(root[x[i]],zz[i],1,1,m);update(root[yy[i]],zz[i],1,1,m);update(root[lca],zz[i],-1,1,m);if(f[lca][0])update(root[f[lca][0]],zz[i],-1,1,m);
    103     }
    104     dfs(1);
    105     for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    106 }

    我还是太弱了,orzorz。

  • 相关阅读:
    单链表的实现C语言版
    顺序表的基本方法实现C语言版
    算法
    Redis
    Linux安装python3.6.1
    Markdown 基本使用手册
    设计Django个人博客网站
    RabbitMQ消息队列
    堡垒机 Paramiko 模块
    进程、线程、协程总结
  • 原文地址:https://www.cnblogs.com/leom10/p/11044190.html
Copyright © 2011-2022 走看看