zoukankan      html  css  js  c++  java
  • bzoj4182 Shopping

    点分治+单调队列优化多重背包+dfs序优化背包合并

    连通块算是一种依赖背包

    但是背包合并是O(m^2)的。因为x必须考虑之前儿子的选法

    trick:dfs序优化

    点分治统计过G的连通块,以G为根找到dfs序

    子树连续一段,不选择x,x的子树都不能选,选择x才考虑子树怎么选

    倒序dfs序处理,每次加入一个x物品,而不是背包合并。因为我们点分治考虑的是G为根,所以x不会为根,只用考虑x对全局的贡献

    f[x][*]<-f[fdfn[dfn[x]+1]][*]  ||   f[fdfn[dfn2[x]+1]][*]

    意义是考虑到x,dfs序中前dfn[x]个做背包的结果,x不选择保证不从子树位置转移,所以选择的情况一定是一个连通块样子

    (点分治换成dot可以牺牲一个log搞出以x为根dfs序,算出x为根的连通块答案)

    代码:

    注意,多组数据vis清空,sz重新找,单调队列大小是m

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=505;
    const int M=4004;
    const int inf=0x3f3f3f3f;
    int n,m;
    int w[N],c[N],d[N];
    int ans;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int sz[N];
    int nowsz,rt;
    bool vis[N];
    void fin(int x,int fa){
        sz[x]=1;
        int mxsz=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[y]) continue;
            fin(y,x);
            sz[x]+=sz[y];
            mxsz=max(mxsz,sz[y]);
        }
        mxsz=max(mxsz,nowsz-sz[x]);
        if(mxsz<=nowsz/2) rt=x;
    }
    int dfn[N],dfn2[N],df;
    int fdfn[N];
    int f[N][M];
    int q[M],l,r;
    void wrk(int x){
    //    memset(f[x],0,sizeof f[x]);
    //    cout<<" wrk x "<<x<<" c "<<c[x]<<" d "<<d[x]<<" w "<<w[x]<<" d[133] "<<d[133]<<endl; 
        for(reg i=0;i<=m;++i) f[x][i]=f[fdfn[dfn2[x]+1]][i];
        int y=fdfn[dfn[x]+1];
    ///    cout<<"with "<<y<<endl;
        int lp=0;
        for(reg yu=0;yu<min(c[x],m+1);++yu){
            l=1,r=0;
            for(reg p=0;p*c[x]+yu<=m;++p){
                ++lp;
            //    cout<<" infor "<<yu<<" "<<p<<" "<<l<<" "<<r<<endl;
                while(l<=r&&p-q[l]>d[x]) ++l;
                if(l<=r) f[x][p*c[x]+yu]=max(f[x][p*c[x]+yu],f[y][q[l]*c[x]+yu]+(p-q[l])*w[x]);
                while(l<=r&&f[y][q[r]*c[x]+yu]-q[r]*w[x]<=f[y][p*c[x]+yu]-p*w[x]) --r;
                q[++r]=p;
            }
        }
    //    cout<<" bac x "<<x<<" lp "<<lp<<endl;
    }
    void dfs(int x,int fa){
        dfn[x]=++df;fdfn[df]=x;
        sz[x]=1;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[y]) continue;
            dfs(y,x);    
            sz[x]+=sz[y];
        }
        dfn2[x]=df;
    }
    void divi(int x){
        rt=0;
        fin(x,0);
        df=0;
        dfs(rt,0);
        fdfn[df+1]=0;
        for(reg i=df;i>=1;--i) wrk(fdfn[i]);
        
        for(reg j=0;j<=m;++j){
            ans=max(ans,f[rt][j]);
        }
        int tmp=rt;
        vis[tmp]=1;
        for(reg i=hd[tmp];i;i=e[i].nxt){
            int y=e[i].to;
            if(vis[y]) continue;
            nowsz=sz[y];
            divi(y);
        }
    }
    void clear(){
        memset(hd,0,sizeof hd);
        cnt=0;df=0;ans=0;
        memset(vis,0,sizeof vis);
    }
    int main(){
        int t;rd(t);
        while(t--){
            clear();
            rd(n);rd(m);
            for(reg i=1;i<=n;++i) rd(w[i]);
            for(reg i=1;i<=n;++i) rd(c[i]);
            for(reg i=1;i<=n;++i) rd(d[i]);
            int x,y;
            for(reg i=1;i<n;++i){
                rd(x);rd(y);add(x,y);add(y,x);
            }
            nowsz=n;
            divi(1);
            printf("%d
    ",ans);
    //        prt(vis,1,n);
    //        if(t==1)return 0;
        }
        return 0;
    }
    
    }
    signed main(){
        freopen("data.in","r",stdin);
        freopen("my.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/20 7:29:17
    */
  • 相关阅读:
    codeforces 940E 思维,dp
    codeforces 469D 2-SAT
    Codeforces 937D dfs
    Educational Codeforces Round 39 (Rated for Div. 2) D dp E 贪心
    Codeforces Round #469 (Div. 2) D 数学递归 E SCC缩点
    Wannafly挑战赛11 D 白兔的字符串 Hash
    Codeforces Round #470 (Div 2) B 数学 C 二分+树状数组 D 字典树
    UVA
    最小生成树(改了两个板子写的)道路建设
    poj1125 基础最短路
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10563245.html
Copyright © 2011-2022 走看看