bzoj 4712

首先是动态dp了嘛...

然后考虑怎么做:首先列出dp方程,大概长这样:

$f[i]=min(v[i],\sum f[to])$

看着不太像动态dp呀...

考虑拿出重儿子的贡献,然后套模型,大概能构造出一个这样的东西:

设$g_{i}=\sum f_{to}[to!=son]$

$\begin{pmatrix} f_{i}\\0 \end{pmatrix}$ = $\begin{pmatrix} g_{i}&v_{i}\\ \infty& 0 \end{pmatrix}$  $\begin{pmatrix} f_{son}\\0 \end{pmatrix}$

然后套线段树维护矩阵即可

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#define rt1 (rt<<1)
#define rt2 (rt<<1)|1
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3fll;
struct MAT
{
    ll a[2][2];
    friend MAT operator * (MAT x,MAT y)
    {
        MAT ret;
        ret.a[0][0]=min(x.a[0][0]+y.a[0][0],x.a[0][1]+y.a[1][0]);
        ret.a[0][1]=min(x.a[0][1]+y.a[1][1],x.a[0][0]+y.a[0][1]);
        ret.a[1][0]=min(x.a[1][1]+y.a[1][0],x.a[1][0]+y.a[0][0]);
        ret.a[1][1]=min(x.a[1][1]+y.a[1][1],x.a[1][0]+y.a[0][1]);
        return ret;
    }
}ori[200005];
MAT tree[800005];
int ed[200005],dep[200005],nnum[200005],onum[200005],f[200005],ttop[200005],siz[200005],son[200005];
ll F[200005],G[200005],w[200005];
char s[2];
vector <int> v[200005];
int n,tot;
void dfs(int x,int fx)
{
    siz[x]=1,f[x]=fx,dep[x]=dep[fx]+1;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx)continue;
        dfs(to,x);
        siz[x]+=siz[to],son[x]=(siz[to]>siz[son[x]])?to:son[x];
    }
}
void redfs(int x,int fx,int topx)
{
    ttop[x]=topx,nnum[x]=++tot,onum[tot]=x;
    if(son[x])redfs(son[x],x,topx),ed[x]=ed[son[x]];
    else ed[x]=x,F[x]=G[x]=w[x];
    F[x]=F[son[x]];
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx||to==son[x])continue;
        redfs(to,x,to);
        G[x]+=F[to];
    }
    F[x]=min(w[x],F[x]+G[x]);
}
void buildtree(int rt,int l,int r)
{
    if(l==r)
    {
        int p=onum[l];
        ori[p].a[0][0]=G[p],ori[p].a[1][0]=inf,ori[p].a[1][1]=0,ori[p].a[0][1]=w[p];
        if(!son[p])ori[p].a[1][0]=0;
        tree[rt]=ori[p];
        return;
    }
    int mid=(l+r)>>1;
    buildtree(rt1,l,mid),buildtree(rt2,mid+1,r);
    tree[rt]=tree[rt1]*tree[rt2];
}
void update(int rt,int l,int r,int posi)
{
    if(l==r){tree[rt]=ori[onum[posi]];return;}
    int mid=(l+r)>>1;
    if(posi<=mid)update(rt1,l,mid,posi);
    else update(rt2,mid+1,r,posi);
    tree[rt]=tree[rt1]*tree[rt2];
}
MAT query(int rt,int l,int r,int lq,int rq)
{
    if(l>=lq&&r<=rq)return tree[rt];
    int mid=(l+r)>>1;
    if(rq<=mid)return query(rt1,l,mid,lq,rq);
    else if(lq>mid)return query(rt2,mid+1,r,lq,rq);
    else return query(rt1,l,mid,lq,rq)*query(rt2,mid+1,r,lq,rq);
}
void ins(int p,ll t)
{
    ori[p].a[0][1]+=t-w[p];
    if(!son[p])ori[p].a[0][0]+=t-w[p];
    w[p]=t;
    while(p)
    {
        MAT m0=query(1,1,n,nnum[ttop[p]],nnum[ed[p]]);
        update(1,1,n,nnum[p]);
        MAT m1=query(1,1,n,nnum[ttop[p]],nnum[ed[p]]);
        p=f[ttop[p]];
        if(!p)break;
        ori[p].a[0][0]+=m1.a[0][0]-m0.a[0][0];
    }
}
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        v[x].push_back(y),v[y].push_back(x);
    }
    dfs(1,0),redfs(1,0,1);
    buildtree(1,1,n);
    int m=read();
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='Q')
        {
            int x=read();
            MAT ret=query(1,1,n,nnum[x],nnum[ed[x]]);
            printf("%lld\n",ret.a[0][0]);
        }else
        {
            int x=read(),y=read();
            ins(x,w[x]+y);
        }
    }
    return 0;
}

 

posted @ 2019-07-02 08:40  lleozhang  Views(192)  Comments(0Edit  收藏  举报
levels of contents