zoukankan      html  css  js  c++  java
  • BZOJ4557 JLOI2016侦察守卫(树形dp)

      下称放置守卫的点为监控点。设f[i][j]为i子树中深度最大的未被监视点与i的距离不超过j时的最小代价,g[i][j]为i子树中距离i最近的监控点与i的距离不超过j且i子树内点全部被监视时的最小代价。开始觉得这只能设成三维状态对这种二维的纠结了半天要怎么处理子树内有点未被监视但监控点的范围可以延伸到子树外的情况冷静了好长时间终于发现自己果然是个弱智既然子树内有点要被监视在子树外监控这个点的点之后带来的效果就肯定要比子树内的监控点强所以根本不用管子树内的监控点了不写标点发泄一下内心的心态爆炸。

      考虑转移。对于f[i][j],显然有f[i][j]=Σf[son][j-1],f[i][0]=Σg[son][d](g本身就可以看做是f的第二维在负数下的拓展)。对于g[i][j],枚举与i号点最近的监控点在哪棵子树,则有g[i][j]=g[k][j-1]+Σf[son][d-j-1]。g[i][d]特殊处理,如果其不要求被监视则g[i][d]=Σg[son][d],虽然不太符合定义但正确性显然,否则g[i][d]=g[k][d-1]+Σg[son][d]。然后考虑将i号点设置为监控点,则有g[i][0]=a[i]+Σf[son][d-1]。最后对所有f和g取min。

      感觉写的莫名其妙,也莫名其妙就过掉了。要是没法1A的话估计得调一年。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 500010
    #define inf 1000000000
    #define M 22
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int n,d,m,a[N],p[N],f[N][M],g[N][M],t=0;
    bool flag[N];
    struct data{int to,nxt;
    }edge[N<<1];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k,int from)
    {
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from) dfs(edge[i].to,k);
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from)
        {
            f[k][0]+=g[edge[i].to][d];
            for (int j=1;j<=d;j++)
            f[k][j]+=f[edge[i].to][j-1];
        }
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from) g[k][0]+=f[edge[i].to][d-1];
        g[k][0]+=a[k];for (int i=1;i<=d;i++) g[k][i]=g[k][0];
        for (int j=1;j<d;j++)
        {
            int tot=0;
            for (int i=p[k];i;i=edge[i].nxt)
            if (edge[i].to!=from) tot+=f[edge[i].to][d-j-1];
            for (int i=p[k];i;i=edge[i].nxt)
            if (edge[i].to!=from) g[k][j]=min(g[k][j],g[edge[i].to][j-1]-f[edge[i].to][d-j-1]+tot);
        }
        int tot=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from) tot+=g[edge[i].to][d];
        if (flag[k])
        {
            for (int i=p[k];i;i=edge[i].nxt)
            if (edge[i].to!=from) g[k][d]=min(g[k][d],g[edge[i].to][d-1]-g[edge[i].to][d]+tot);
        }
        else g[k][d]=tot;
        for (int i=1;i<=d;i++) g[k][i]=min(g[k][i],g[k][i-1]);
        f[k][0]=min(f[k][0],g[k][d]);
        for (int i=1;i<=d;i++) f[k][i]=min(f[k][i],f[k][i-1]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4557.in","r",stdin);
        freopen("bzoj4557.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),d=read();
        for (int i=1;i<=n;i++) a[i]=read();
        m=read();
        for (int i=1;i<=m;i++) flag[read()]=1;
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read();
            addedge(x,y),addedge(y,x);
        }
        dfs(1,1);
        cout<<g[1][d];
        return 0;
    }
  • 相关阅读:
    beta冲刺1
    凡事预则立-于Beta冲刺前
    SDN第二次作业
    事后诸葛亮(团队)
    SDN第一次上机作业
    冲刺总结随笔
    Alpha第三天
    Alpha第二天
    Alpha冲刺博客集
    项目需求分析(团队)
  • 原文地址:https://www.cnblogs.com/Gloid/p/9892966.html
Copyright © 2011-2022 走看看