• [洛谷P4556] 雨天的尾巴


    这道题可以用线段树合并做,网上的题解基本上都是线段树合并的。

    但是为什么我就偏偏要用dsu on tree......

    题目传送门

    dsu on tree的方法类似[CF1009F] Dominant Indices(这是我之前写的题解)。

    但是这道题要把树链操作变成某点到根的操作,最后统计子树贡献和。

    子树贡献有正有负,不能像那道题那样用堆维护最大值(在这卡了半天)。

    因为那道题只有加,这道题有加有减。

    可能加上之后又减掉了,但是堆给出的最大值会是减掉之前的值(因为值更大)。

    所以用线段树维护一下最大值。

    这个线段树是比较简单的,支持单点修改即可。

    查询时必然查询的是0~n的全局最大值。

    所以就是线段树根的最大值喽。

    注意线段树必须有一个0的位置。

    因为如果没有救济粮的话要输出0。

    至于如果有多种救济粮存放次数一样,怎么输出编号最小的。

    在线段树向上更新的时候:(具体见代码第82行)

    要这么写:if(mv[num<<1]>=mv[num<<1|1])

    不能这么写:if(mv[num<<1]>mv[num<<1|1])

    这样可以保证如果两边的最大值一样,会用左边的(也就是编号较小的)来更新。

    怕卡,lca用的树剖。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 using namespace std;
      6 
      7 int n,m;
      8 int hd[100005],nx[200005],to[200005],ec;
      9 int fir[100005],bes[400005],kd[400005],fl[400005],qc;
     10 int f[100005],son[100005],sz[100005],d[100005],tp[100005];
     11 
     12 void edge(int af,int at)
     13 {
     14     to[++ec]=at;
     15     nx[ec]=hd[af];
     16     hd[af]=ec;
     17 }
     18 
     19 void mark(int p,int pkd,int pfl)
     20 {
     21     kd[++qc]=pkd;
     22     fl[qc]=pfl;
     23     bes[qc]=fir[p];
     24     fir[p]=qc;
     25 }
     26 
     27 void pre(int p,int fa)
     28 {
     29     f[p]=fa;
     30     d[p]=d[fa]+1;
     31     sz[p]=1;
     32     for(int i=hd[p];i;i=nx[i])
     33     {
     34         if(to[i]==fa)continue;
     35         pre(to[i],p);
     36         sz[p]+=sz[to[i]];
     37         if(sz[to[i]]>sz[son[p]])son[p]=to[i];
     38     }
     39 }
     40 
     41 void findtp(int p)
     42 {
     43     if(p==son[f[p]])tp[p]=tp[f[p]];
     44     else tp[p]=p;
     45     for(int i=hd[p];i;i=nx[i])
     46         if(to[i]!=f[p])findtp(to[i]);
     47 }
     48 
     49 int lca(int x,int y)
     50 {
     51     while(tp[x]!=tp[y])
     52         d[tp[x]]>d[tp[y]]?x=f[tp[x]]:y=f[tp[y]];
     53     return d[x]<d[y]?x:y;
     54 }
     55 
     56 int ans[100005];
     57 int lb[400005],rb[400005],mc[400005],mv[400005];
     58 
     59 void build(int num,int l,int r)
     60 {
     61     lb[num]=l,rb[num]=r;
     62     if(l==r)
     63     {
     64         mc[num]=l;
     65         return;
     66     }
     67     int mid=(l+r)>>1;
     68     build(num<<1,l,mid);
     69     build(num<<1|1,mid+1,r);
     70 }
     71 
     72 void update(int num,int p,int v)
     73 {
     74     if(lb[num]==rb[num])
     75     {
     76         mv[num]+=v;
     77         return;
     78     }
     79     int mid=(lb[num]+rb[num])>>1;
     80     if(p<=mid)update(num<<1,p,v);
     81     else update(num<<1|1,p,v);
     82     if(mv[num<<1]>=mv[num<<1|1])
     83         mv[num]=mv[num<<1],mc[num]=mc[num<<1];
     84     else
     85         mv[num]=mv[num<<1|1],mc[num]=mc[num<<1|1];
     86 }
     87 
     88 void add(int p)
     89 {
     90     for(int i=hd[p];i;i=nx[i])
     91         if(to[i]!=f[p])add(to[i]);
     92     for(int i=fir[p];i;i=bes[i])
     93         update(1,kd[i],fl[i]);
     94 }
     95 
     96 void del(int p)
     97 {
     98     for(int i=hd[p];i;i=nx[i])
     99         if(to[i]!=f[p])del(to[i]);
    100     for(int i=fir[p];i;i=bes[i])
    101         update(1,kd[i],-fl[i]);
    102 }
    103 
    104 void dsu(int p,int keep)
    105 {
    106     for(int i=hd[p];i;i=nx[i])
    107         if(to[i]!=f[p]&&to[i]!=son[p])
    108             dsu(to[i],0);
    109     if(son[p])dsu(son[p],1);
    110     for(int i=hd[p];i;i=nx[i])
    111         if(to[i]!=f[p]&&to[i]!=son[p])
    112             add(to[i]);
    113     for(int i=fir[p];i;i=bes[i])
    114         update(1,kd[i],fl[i]);
    115     ans[p]=mc[1];
    116     if(!keep)del(p);
    117 }
    118 
    119 int main()
    120 {
    121     scanf("%d%d",&n,&m);
    122     for(int i=1;i<n;i++)
    123     {
    124         int a,b;
    125         scanf("%d%d",&a,&b);
    126         edge(a,b);
    127         edge(b,a);
    128     }
    129     pre(1,1);
    130     findtp(1);
    131     build(1,0,100000);
    132     for(int i=1;i<=m;i++)
    133     {
    134         int x,y,z;
    135         scanf("%d%d%d",&x,&y,&z);
    136         int l=lca(x,y);
    137         mark(x,z,1);
    138         mark(y,z,1);
    139         mark(l,z,-1);
    140         if(l!=1)mark(f[l],z,-1);
    141     }
    142     dsu(1,1);
    143     for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    144     return 0;
    145 }
    洛谷P4556 雨天的尾巴
  • 相关阅读:
    十大排序算法详解,基本思想+动画演示+C语言实现,太肝了!
    宛如一个未来穿越者,终年33岁的印度数学天才,大数学家哈代说“他发现并创造了数学”
    编程的相关概念
    android中ScrollView嵌套ListView或GridView显示位置问题
    炫酷MD风之dialog各种对话框
    (转载)new Thread的弊端及Java四种线程池的使用
    (转载)Android开发——Android中常见的4种线程池(保证你能看懂并理解)
    (转)android import library switch语句报错case expressions must be constant expressions
    eclipse中将一个项目作为library导入另一个项目中
    (转)Android四大组件——Activity跳转动画、淡出淡入、滑出滑入、自定义退出进入
  • 原文地址:https://www.cnblogs.com/cervusy/p/9594486.html
Copyright © 2020-2023  润新知