zoukankan      html  css  js  c++  java
  • BZOJ 4712 洪水 (线段树+树剖动态维护DP)

    题目大意:略 题目传送门 

    数据结构好题,但据说直接上动态DP会容易处理不少,然而蒟蒻不会。一氧化碳大爷说还有一个$log$的做法,然而我只会$log^{2}$的.. 

    考虑静态时如何处理,设$f[x]$表示堵住$x$这棵子树的最小花费,$g[x]$表示$x$所有子节点的$f[x]$总和,$a[x]$表示x点的权值

    容易得到方程$f[x]=min(g[x],a[x])$

    那么如果点权是动态的呢?

    本题中的修改操作只会把点权增加

    而真正对答案产生影响的,是某些节点的$f$值取的是$g$值还是$a$值

    只有取的值发生改变,$f$值才可能改变,从而对它的祖先节点们产生影响

    当我们修改一个点$x$的权值时,$a[x]$会增加,$g[x]$不变,$f[x]$的取值可能会发生改变,要么由取$a$变成取$g$,要么不变,且$f[x]$只可能增加而不会减少

    而对于$x$的所有祖先节点的来说,要么由取$g$变成取$a$,要么不变

    也就是说,只有我们修改的那个节点,$f$的取值能从$a$变成$g$,且它的$g$值不变

    修改操作影响的其他节点,都是从$g$变成$a$,且这些节点的$a$值不变

    所以说从$g$变成$a$这种操作,最多出现$n+m$次,这部分我们可以暴力处理

    如果我们修改一个节点$x$,可能会有连续的几个祖先会从取$g$变成取$a$,我们暴力修改这些祖先的信息

    直到我们碰到了一个祖先,原来是取$g$,修改后还是取$g$,而这样的祖先节点一定是在一条连续的链上的,且它们的数量可能很大,我们称这样的一条链为$T$

    考虑树剖+线段树处理这部分祖先的信息,从最下面的点开始,每次拎出来一条重链,先判断$T$的顶端是不是 重链头的某个祖先节点

    那么如何判断$T$的顶端是否在重链头的上面呢?

    发现如果原来取$g$,现在还取$g$,设修改值是del$T$$a$ (注意这个修改值不一定是修改操作里的那个值!!!而是由链$T$的底端的那个节点的$f$的变化值)

    $T$上每一个节点都满足$g[x]+delta leq a[x]$,即$a[x]-g[x] geq delta$ 

    我们用线段树维护每个节点的$a[x]-g[x]$值

    如果是,暴力修改这部分重链,然后跳掉上面一条重链继续处理

    如果不是,说明$T$的顶端在重链内部,前缀/后缀最小值是具有单调性的,二分找到$T$的顶端即可

    链$T$顶端的父节点的$f$值只能是由$g$变成$a$,或者不变。如果改变了,就不断重复上述过程即可

    复杂度$O(nlog^{2}n)$

    代码实现比较复杂

      1 #include <vector>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 200010
      6 #define ll long long
      7 #define dd double
      8 #define inf 0x3f3f3f3f3f3f3f3fll
      9 using namespace std;
     10 
     11 int gint()
     12 {
     13     int ret=0,fh=1;char c=getchar();
     14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     16     return ret*fh;
     17 }
     18 void gchar(char *s)
     19 {
     20     int cnt=0;char c=getchar();
     21     while(c<'A'||c>'Z'){c=getchar();}
     22     while(c>='A'&&c<='Z'){s[cnt++]=c;c=getchar();}
     23     s[cnt]='
    ';
     24 }
     25 
     26 struct Edge{
     27 int head[N1],to[N1<<1],nxt[N1<<1],cte;
     28 void ae(int u,int v)
     29 {cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte;}
     30 }e;
     31 
     32 struct SEG{
     33 ll mi[N1<<2],tag[N1<<2];
     34 inline void pushup(int rt){ mi[rt]=min(mi[rt<<1],mi[rt<<1|1]); }
     35 void pushdown(int rt)
     36 {
     37     if(!tag[rt]) return;
     38     mi[rt<<1]+=tag[rt]; mi[rt<<1|1]+=tag[rt];
     39     tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt];
     40     tag[rt]=0;
     41 }
     42 void build(int *a,ll *g,int *id,int l,int r,int rt)
     43 {
     44     if(l==r) { mi[rt]=1ll*a[id[l]]-g[id[l]]; return; }
     45     int mid=(l+r)>>1;
     46     build(a,g,id,l,mid,rt<<1);
     47     build(a,g,id,mid+1,r,rt<<1|1);
     48     pushup(rt);
     49 }
     50 void update(int L,int R,int l,int r,int rt,ll w)
     51 {
     52     if(L<=l&&r<=R){ mi[rt]+=w; tag[rt]+=w; return; }
     53     int mid=(l+r)>>1; pushdown(rt);
     54     if(L<=mid) update(L,R,l,mid,rt<<1,w);
     55     if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
     56     pushup(rt);
     57 }
     58 ll query(int L,int R,int l,int r,int rt)
     59 {
     60     if(L<=l&&r<=R) return mi[rt];
     61     int mid=(l+r)>>1; pushdown(rt); ll ans=inf;
     62     if(L<=mid) ans=min(ans,query(L,R,l,mid,rt<<1));
     63     if(R>mid) ans=min(ans,query(L,R,mid+1,r,rt<<1|1));
     64     return ans;
     65 }
     66 }s;
     67 
     68 int n,m;
     69 int a[N1];
     70 namespace Split{
     71 int fa[N1],son[N1],tp[N1],sz[N1],dep[N1],st[N1],id[N1],tot; ll g[N1],f[N1];
     72 void dfs1(int u,int dad)
     73 {
     74     int j,v; sz[u]=1;
     75     for(j=e.head[u];j;j=e.nxt[j])
     76     {
     77         v=e.to[j]; if(v==dad) continue;
     78         dep[v]=dep[u]+1; fa[v]=u; dfs1(v,u);
     79         sz[u]+=sz[v]; son[u]=sz[v]>sz[son[u]]?v:son[u];
     80         g[u]+=f[v];
     81     }
     82     if(sz[u]>1) f[u]=min(1ll*a[u],g[u]);
     83     else f[u]=a[u],g[u]=inf;
     84 }
     85 void dfs2(int u)
     86 {
     87     int j,v; st[u]=++tot; id[tot]=u;
     88     if(son[u]){ tp[son[u]]=tp[u]; dfs2(son[u]); }
     89     for(j=e.head[u];j;j=e.nxt[j])
     90     {
     91         v=e.to[j]; if(v==fa[u]||v==son[u]) continue;
     92         tp[v]=v; dfs2(v);
     93     }
     94 }
     95 void init()
     96 {
     97     dfs1(1,-1); tp[1]=1; dfs2(1);
     98     s.build(a,g,id,1,n,1);
     99 }
    100 };
    101 using Split::fa; using Split::st;
    102 using Split::id; using Split::tp;
    103 
    104 void update(int x,ll w)
    105 {
    106     ll gx,dt,gu,mi; int u,flag,l,r,mid,ans;
    107     gx=a[x]-s.query(st[x],st[x],1,n,1);
    108     s.update(st[x],st[x],1,n,1,w); 
    109     if(a[x]>=gx){ return; } //x:g->g
    110     dt=min(gx-a[x],w); x=fa[x];
    111     while(x){
    112     
    113     u=x; flag=0;
    114     while(u)
    115     {
    116         gu=a[u]-s.query(st[u],st[u],1,n,1);
    117         s.update(st[u],st[u],1,n,1,-dt); 
    118         if(a[u]<=gu) break; 
    119         if(gu+dt>a[u]) dt=a[u]-gu; 
    120         else{ flag=1; u=fa[u]; break; } 
    121         u=fa[u];
    122     }
    123     if(!flag) break;
    124     while(u)
    125     {
    126         mi=s.query(st[tp[u]],st[u],1,n,1);
    127         if(mi>=dt){
    128             s.update(st[tp[u]],st[u],1,n,1,-dt);
    129             u=fa[tp[u]];
    130         }else{
    131             l=st[tp[u]]; r=st[u]; ans=0;
    132             while(l<=r)
    133             {
    134                 mid=(l+r)>>1; 
    135                 if(s.query(mid,st[u],1,n,1)>=dt) ans=id[mid],r=mid-1;
    136                 else l=mid+1;
    137             }
    138             if(!ans){ x=u; break; }
    139             s.update(st[ans],st[u],1,n,1,-dt);
    140             x=fa[ans]; 
    141             break;
    142         }
    143     }
    144     
    145     }
    146 }
    147 ll query(int x){ return min(1ll*a[x],1ll*a[x]-s.query(st[x],st[x],1,n,1)); }
    148 
    149 int main()
    150 {
    151     scanf("%d",&n);
    152     int i,j,k,x,y; char str[10];
    153     for(i=1;i<=n;i++) a[i]=gint();
    154     for(i=1;i<n;i++){ x=gint(); y=gint(); e.ae(x,y); e.ae(y,x); }
    155     Split::init();
    156     scanf("%d",&m); 
    157     for(j=1;j<=m;j++)
    158     {
    159         gchar(str);
    160         if(str[0]=='Q'){
    161             x=gint();
    162             printf("%lld
    ",query(x));
    163         }else{
    164             x=gint(); y=gint(); if(!y) continue;
    165             update(x,y); a[x]+=y;
    166         }
    167     }
    168     return 0;
    169 }
  • 相关阅读:
    【转】请说出三种减少页面加载时间的方法。
    【转】Web前端性能优化——如何提高页面加载速度
    【转】数据分析sql常用整理
    【转】消息中间件系列之简单介绍
    Could not load file or assembly 'System.Core, Version=2.0.5.0 和autofac冲突的问题
    云主机与传统主机性能对比表
    真假云主机,VPS资料集合
    将网站部署到windows2003 iis6之后,出现asp.net程序页面无法访问情况
    想当然是编程最大的坑,记更新删除过期cookie无效有感
    FlashBuilder(FB/eclipse) 打开多个无效
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10267477.html
Copyright © 2011-2022 走看看