BZOJ4712 洪水

这题考场上拿到了50分暴力分海星

首先考虑暴力怎么搞,设dis[i]表示切断i节点与叶子的联系的最优价值

tot[i]表示i节点的所有儿子的dis之和,对于叶子结点,他的tot值为0,dis为val,很容易的得到转移方程dis[i]=min(val[i],tot[i]),

每次更新只会影响到它的父亲以及父亲往上的一条链,直到根节点,所以就可以O(hm)的解决这道题

这是50分做法

那50->100是质的飞越,那是DDP,当然也可以二分,但是我不会

改变一下原先的定义,tot[i]为切断i节点与他所有轻儿子的联系

那么转移方程改变为dis[i]=min(val[i],tot[i]+dis[son[i]])

重儿子展开就是dis[i]=min(val[i],tot[i]+min(val[son[i]],dis[son[son[i]]]+tot[son[i]]))

在一条重链上,一个节点的改变会影响链头的fa的tot值和所有的dis值,

对于tot值单独在外面开一个数组维护,每次需要更新,而dis值在线段树上维护,

如何在线段树上维护?

对于这个东西把它转化成矩阵乘,重新定义一下矩阵乘

乘为加,加为取min,

构造的矩阵为2*2的,左上是0,右上是dis[i],左下是inf,右下是tot[i]。

乘的时候是从右往左乘。

更新的时候需要将链头的fa的tot值中链头原先的dis值,然后更新之后加上新的dis值

对于每次询问都需要访问从链底到当前位置。

这题有点卡常,需要用快读。

代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define LL long long
#define mid ((l+r)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define ls k<<1
#define rs k<<1|1
#define t(rt,a,b) tr[rt].f[a][b] 
using namespace std;
const int N=200005;
const LL inf=1e18;
int n,m,cnt,head[N],fa[N],tot;
int in[N],dep[N],top[N],dfn[N],id[N],siz[N],son[N],bot[N];
LL vl[N],f[N],g[N];
vector<int>q;
struct node{
    int to,nxt;
}e[N<<1];
struct martix{
    LL f[2][2];
    martix(){
        f[0][0]=f[0][1]=f[1][0]=f[1][1]=0;
    }
    inline void init(){
        f[0][1]=f[1][0]=inf;
    }
    inline void mx(){
        f[0][0]=f[0][1]=f[1][0]=f[1][1]=inf;
    }
};
martix tr[N<<2];
martix operator *(const martix &a,const martix &b){
    martix res;
    res.mx();
    for(int k=0;k<2;++k)
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                res.f[i][j]=min(res.f[i][j],a.f[i][k]+b.f[k][j]);
    return res;
}
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
inline void add(int from,int to){
    e[++cnt]=(node){to,head[from]};
    head[from]=cnt;in[to]++;
}
void dfs1(int x,int f,int deep){
    fa[x]=f;siz[x]=1;dep[x]=deep;
    int maxson=-1;
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=f){
            dfs1(e[i].to,x,deep+1);
            siz[x]+=siz[e[i].to];
            if(siz[e[i].to]>maxson){
                son[x]=e[i].to;
                maxson=siz[e[i].to];
            }
        }
}
void dfs2(int x,int topf){
    f[x]=vl[x];dfn[x]=++tot;id[tot]=x;top[x]=topf;
    if(son[x]){
        dfs2(son[x],topf);
        bot[x]=bot[son[x]];
    }
    else bot[x]=x;
    for(int i=head[x];i;i=e[i].nxt){
        if(e[i].to==son[x]||e[i].to==fa[x])
            continue;
        dfs2(e[i].to,e[i].to);
        g[x]+=f[e[i].to];
    }
    if(in[x])f[x]=min(f[x],f[son[x]]+g[x]);
}
inline void update(int k){
    tr[k]=tr[rs]*tr[ls];
} 
void build(int k,int l,int r){
    if(l==r){
        t(k,1,0)=inf;
        t(k,0,1)=vl[id[l]];
        t(k,1,1)=g[id[l]];
        return ;
    }
    build(rson);build(lson);
    update(k);
}
martix ask(int k,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        return tr[k];
    }
    martix res;
    res.init();
    if(y>mid)res=res*ask(rson,x,y);
    if(x<=mid)res=res*ask(lson,x,y);
    return res;
}
inline void mark_f(int x){
    while(top[x]!=1){
        martix res=ask(1,1,n,dfn[top[x]],dfn[bot[x]]);
        q.push_back(res.f[0][1]);
        x=fa[top[x]];
    }
}
void change(int k,int l,int r,int x){
    if(l==r&&l==x){
        t(k,0,1)=vl[id[x]];
        t(k,1,1)=g[id[x]];
        return ;
    }
    if(x<=mid)change(lson,x);
    else change(rson,x);
    update(k);
}
inline void chenge(int x){
    q.clear();
    mark_f(x);
    int tmp=0;
    while(top[x]!=1){
        g[fa[top[x]]]-=q[tmp++];
        change(1,1,n,dfn[x]);
        g[fa[top[x]]]+=ask(1,1,n,dfn[top[x]],dfn[bot[x]]).f[0][1];
        x=fa[top[x]];
    }
    change(1,1,n,dfn[x]);
}
int main(){
    n=read();
    for(int i=1;i<=n;++i)
        vl[i]=read(),in[i]=-1;
    in[1]++;
    int x,y;
    for(int i=1;i<n;++i){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    m=read();
    char c[3];
    while(m--){
        scanf("%s%d",c+1,&x);
        if(c[1]=='Q')
            printf("%lld
",ask(1,1,n,dfn[x],dfn[bot[x]]).f[0][1]);
        else{
            y=read();
            vl[x]+=y;
            chenge(x);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sanjinliushi/p/11626341.html