bzoj2164 采矿(树形背包dp+线段树优化+链剖)

首先我们如果能预处理出dp[x][j]表示x子树内分配j个人最大获益,然后每次询问O(m)的循环一下,还需要知道在链上某一个点分配m-j个人的最大获益,我们发现这个东西可以放在线段树上树剖来维护。但是有修改的话我们预处理的那个dp数组就gg了,怎么办呢qaq 我们发现其实这个dp数组也可以直接在线段树上维护!每次线段树信息合并时背包dp合并一下即可,复杂度 O ( m 2 )
因此总的复杂度就是 O ( n l o g n m 2 + C ( l o g 2 n m + l o g n m 2 ) )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20010
int const X=1<<16,Y=(1<<31)-1;
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,A,B,C,son[N],fa[N],dep[N],top[N],sz[N],in[N],out[N],dfn=0;
vector<int>Son[N];
inline int gen(){
    A=((A^B)+B/X+B*X)&Y;B=((A^B)+A/X+A*X)&Y;return (A^B)%C;
}
struct Icefox{
    int a[52];
    int& operator[](int x){return a[x];}
    inline void init(){
        for(int i=1;i<=m;++i) a[i]=gen();sort(a+1,a+m+1);
    }friend Icefox operator+(Icefox a,Icefox b){
        Icefox res;memset(res.a,0,sizeof(res.a));
        for(int i=1;i<=m;++i)
            for(int j=0;j<=i;++j)
                res[i]=max(res[i],a[j]+b[i-j]);return res;
    }
};
inline Icefox Max(Icefox a,Icefox b){
    for(int i=1;i<=m;++i) a[i]=max(a[i],b[i]);
    return a;
}
struct node{
    Icefox x1,x2;//1--选一个 2--选多个
}tr[N<<2];
inline void dfs1(int x){
    sz[x]=1;son[x]=0;
    for(int i=0;i<Son[x].size();++i){
        int y=Son[x][i];fa[y]=x;dep[y]=dep[x]+1;dfs1(y);
        sz[x]+=sz[y];if(sz[y]>sz[son[x]]) son[x]=y;
    }
}
inline void dfs2(int x,int tp){
    in[x]=++dfn;top[x]=tp;
    if(son[x]) dfs2(son[x],tp);
    for(int i=0;i<Son[x].size();++i){
        int y=Son[x][i];if(y!=son[x]) dfs2(y,y);
    }out[x]=dfn;
}
inline void pushup(int p){
    tr[p].x1=Max(tr[p<<1].x1,tr[p<<1|1].x1);
    tr[p].x2=tr[p<<1].x2+tr[p<<1|1].x2;
}
inline void change(int p,int l,int r,int x){
    if(l==r){tr[p].x1.init();tr[p].x2=tr[p].x1;return;}
    int mid=l+r>>1;
    if(x<=mid) change(p<<1,l,mid,x);
    else change(p<<1|1,mid+1,r,x);pushup(p);
}
inline Icefox query(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y) return tr[p].x2;int mid=l+r>>1;
    if(y<=mid) return query(p<<1,l,mid,x,y);
    if(x>mid) return query(p<<1|1,mid+1,r,x,y);
    return query(p<<1,l,mid,x,mid)+query(p<<1|1,mid+1,r,mid+1,y);
}
inline Icefox ask(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y) return tr[p].x1;int mid=l+r>>1;
    if(y<=mid) return ask(p<<1,l,mid,x,y);
    if(x>mid) return ask(p<<1|1,mid+1,r,x,y);
    return Max(ask(p<<1,l,mid,x,mid),ask(p<<1|1,mid+1,r,mid+1,y));
}
inline Icefox doask(int x,int y){
    Icefox res;memset(res.a,0,sizeof(res));
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res=Max(res,ask(1,1,n,in[top[x]],in[x]));x=fa[top[x]];
    }if(in[x]>in[y]) swap(x,y);
    res=Max(res,ask(1,1,n,in[x],in[y]));return res;
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();A=read();B=read();C=read();
    for(int i=2;i<=n;++i) Son[read()].push_back(i);
    dfs1(1);dfs2(1,1);int ofo=read();
    for(int i=1;i<=n;++i) change(1,1,n,in[i]);
    while(ofo--){
        int op=read(),x=read();
        if(!op){change(1,1,n,in[x]);continue;}
        int y=read();Icefox res=query(1,1,n,in[x],out[x]);
        if(x!=y) res=res+doask(fa[x],y);
        printf("%d\n",res[m]);
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80702301
今日推荐