[BZOJ4712] Flood (chain split tree + DP)

The meaning of problems

Give a point to the right of the tree, remove one point takes a corresponding price, Ask every time a sub-tree, find the minimum cost, so that the child can not get any root of the tree leaf sub-tree, the right to a single point of support a positive value increases

Thinking

Set \ (f [i] \) represents the answer i sub-tree, h [i] represents all the sons of f and i, w [i] represents the weight of the value of i is not difficult to list the state transition equation:

f [i] = min (w [i], h [i])

If i is a leaf, it will be assigned to positive infinity h, to avoid some discussion

For the modification operation, as w will only increase, so the value of each array will not reduce
an obvious case, if the value of f has a point equal to w, then no matter how increase its h, its value is not f change (unless it is modified w)

f value is set at some point in the process of modification changes the delta, the point of impact on the ancestor we are divided into four cases (the set point is i, father fa)

  1. \ (Delta = 0 \) , then it will not change ancestor, break (in fact, and almost 2)

  2. \ (F [FA] == W [FA] \) , i.e., modify it has no effect on the value of h f, h [fa] + = delta, delta = 0, the next step will break off

  3. \ (w [fa]> h [fa], w [fa]> h [fa] + delta \) after, i.e. plus delta, f [fa] delta will add

  4. \ (w [fa]> F [FA], w [fa] \ Leq H [FA] + delta \) , i.e. after the addition of delta, f [fa] becomes w [fa]

Chain split tree for maintenance min (wh), h, to modify operation, find the top 3 of the points that satisfy, h value plus some delta these paths, modifying the value of f parent node (parent node satisfies case 2) and then obtain a new delta recursive modification

Each additional recursive time, a point will be described into a case 2, so recursion is O (n) level of recursion tree manipulation is split chain \ ((log ^ 2n) \ O) , so the total time complexity is \ (O (nlog ^ 2n) \)

Code

#include<bits/stdc++.h>
#define N 200005 
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
const ll INF = 100000000000000;
int n,m;
int seg[N],rev[N],top[N],dep[N],fa[N],size[N],son[N],hfu;
ll f[N],h[N],w[N];//f[i]=Min(h[i],w[i])
ll minn[N<<2],sign[N<<2];//由于只会询问叶子节点的h值,所以用sign表示 

struct Edge
{
    int next,to;
}edge[N<<1];int head[N],cnt=1;
void add_edge(int from,int to)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    head[from]=cnt;
}

template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}

void dfs1(int rt)
{
    h[rt]=0;
    size[rt]=1;
    dep[rt]=dep[fa[rt]]+1;
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[rt]) continue;
        fa[v]=rt;
        dfs1(v);
        
        h[rt]+=f[v];
        size[rt]+=size[v];
        if(size[son[rt]]<size[v]) son[rt]=v;
    }
    if(size[rt]==1) h[rt]=INF;//避免讨论,把叶子赋为INF 
    f[rt]=Min(w[rt],h[rt]);
}
void dfs2(int rt)
{
    if(son[rt])
    {
        seg[son[rt]]=++hfu;
        rev[hfu]=son[rt];
        top[son[rt]]=top[rt];
        dfs2(son[rt]);
    }
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[rt]||v==son[rt]) continue;
        seg[v]=++hfu;
        rev[hfu]=v;
        top[v]=v;
        dfs2(v);
    }
}

void pushup(int rt)
{
    minn[rt]=Min(minn[rt<<1],minn[rt<<1|1]);
}
void add_sign(int rt,ll val) 
{
    minn[rt]-=val;
    sign[rt]+=val;
}
void pushdown(int rt)
{
    if(!sign[rt]) return;
    add_sign(rt<<1,sign[rt]);
    add_sign(rt<<1|1,sign[rt]);
    sign[rt]=0;
}
void modify(int rt,int l,int r,int x,int y,ll val)//区间加h 
{
    if(x<=l&&r<=y) return add_sign(rt,val);
    int mid=(l+r)>>1;
    pushdown(rt);
    if(x<=mid) modify(rt<<1,l,mid,x,y,val);
    if(y>mid) modify(rt<<1|1,mid+1,r,x,y,val);
    pushup(rt);
}
void update(int rt,int l,int r,int x)//单点更新
{
    if(l==r)
    {
        minn[rt]=w[rev[l]]-sign[rt];
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(x<=mid) update(rt<<1,l,mid,x);
    else update(rt<<1|1,mid+1,r,x);
    pushup(rt); 
}
ll query_h(int rt,int l,int r,int x)//查询h值 
{
    if(l==r) return sign[rt];
    int mid=(l+r)>>1;
    pushdown(rt);
    if(x<=mid) return query_h(rt<<1,l,mid,x);
    else return query_h(rt<<1|1,mid+1,r,x);
}
ll query_min(int rt,int l,int r,int x,int y,ll det)//找满足minn>det的最左边 
{
    if(x<=l&&r<=y) 
    {
        if(minn[rt]>det) return l;
        if(l==r) return 0; 
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(x<=mid&&y<=mid) return query_min(rt<<1,l,mid,x,y,det);
    if(x>mid&&y>mid) return query_min(rt<<1|1,mid+1,r,x,y,det);
    int R=query_min(rt<<1|1,mid+1,r,x,y,det);
    if(!R||R>mid+1) return R;//如果右边已经不行了就不用查左边了 
    int L=query_min(rt<<1,l,mid,x,y,det);//如果直接左右一起查时间复杂度不对 
    return L ? L : R; 
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        minn[rt]=w[rev[l]]-h[rev[l]];
        sign[rt]=h[rev[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
void modify_edge(int y,ll det)//修改y以上的满足delta < w[i]-h[i]的点 
{
    if(!y||!det) return;
    while(y)
    {
        int c=query_min(1,1,n,seg[top[y]],seg[y],det);//找到最上面的满足条件的 
        if(!c) break; c=rev[c];
        if(c!=top[y])  { modify(1,1,n,seg[c],seg[y],det);y=fa[c];break; }
        modify(1,1,n,seg[top[y]],seg[y],det);
        y=fa[top[y]];
    }
    if(!y) return;
    
    ll t=Min(w[y],query_h(1,1,n,seg[y])),delta;
    modify(1,1,n,seg[y],seg[y],det);
    delta=Min(w[y],query_h(1,1,n,seg[y]))-t;
    modify_edge(fa[y],delta);
}

int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(w[i]);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x);read(y);
        add_edge(x,y);
        add_edge(y,x);
    }
    seg[1]=rev[1]=top[1]=hfu=1;
    dfs1(1); dfs2(1);
    
    build(1,1,n);
    read(m);
    while(m--)
    {
        char op[2]; 
        int x; ll val;
        scanf("%s",op); read(x);
        if(op[0]=='Q') printf("%lld\n",Min(w[x],query_h(1,1,n,seg[x])));
        else
        {
            read(val);
            ll now=Min(w[x],query_h(1,1,n,seg[x])),delta;
            w[x]+=val;
            update(1,1,n,seg[x]);
            delta=Min(w[x],query_h(1,1,n,seg[x]))-now;
            modify_edge(fa[x],delta);
        }
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Chtholly/p/11583844.html