[BZOJ2164]采矿

题目描述

浩浩荡荡的(cg)大军发现了一座矿产资源极其丰富的城市,他们打算在这座城市实施新的采矿战略。

这个城市可以看成一棵有(n)个节点的有根树,我们把每个节点用1到n的整数编号。

为了方便起见,对于任何一个非根节点(v),它任何一个祖先的编号都严格小于(v)

树上的每个节点表示一个矿点,每条边表示一条街道.

作为(cg)大军的一个小队长,你拥有(m)个部下。

你有一张二维的动态信息表,用(T_{i,j})表示第(i)行第(j)列的数据。

当你被允许开采某个区域时,你可以将你的部下分配至各个矿点。

在第(i)个矿点安排(j)个人可以获得(T{i,j})单位的矿产。

允许开采的区域是这样描述的:给你一对矿点((u,v)),保证(v)(u)的祖先(这里定义祖先包括(u)本身);(u)为你控制的区域,可以在以(u)为根的子树上任意分配部下;(u)(v)的简单路径(不包括(u)但包括(v),若(u=v)则包括(u))为探险路径,在该路径上你可以选择至多一个矿点安排部下。你这次开采的收益为安排有部下的矿点的收益之和。

Input

输入的第一行包含(5)个正整数(n、m、A、B、Q。n)为矿点的个数,(m)为部下的数量,(A、B、Q)是与动态信息表有关的数据。

第二行包含(n-1)个正整数,第(i)个数为(F_{i+1}),表示节点(i+1)的父亲。

接下来需要你用下文的方法依次生成(n)组数据,每组数据共(m)个。

其中第(i)组的(m)个数据为信息表中第(i)行的(m)个数据。

紧接着一行包含一个正整数(C),表示事件的数量。

最后给出(C)行,每行描述一个事件。

每个事件会先给出一个(0)(1)的整数。

如果该数为(0),则后面有一个正整数(p),表示动态信息表有更新,你需要生成一组(m)个数据,来替换信息表中第(p)行的(m)个数据。

如果该数为(1),则后面有两个正整数(u、v),表示出现了一个你可以开采的区域,你需要回答这次开采的收益。同一行的各个数之间均用一个空格隔开,没有多余的空格和换行。

数据的生成方法如下:每次生成一组(m)个从小到大排列的数据,替换动态信息表的一行。其中,从小到大第(j)个数替换信息表中第(j)列的数。调用以下代码(m)次并排序得到一组数据。(注意可能会出现重复的数)函数GetInt A←((A xor B)+(B div X)+(B * X))and Y B←((A xor B)+(A div X)+(A * X))and Y 返回(A xor B)mod Q ,(X=2^{16})(2的16次方),(Y=2^{31}-1)(2的31次方-1),xor为位异或运算,div为整除运算,and为位且运算,mod为取余运算。由于只保留了低31位,易得我们不用考虑数据的溢出问题。(注意每次A和B都会被改变)

对于(100\%)的数据(1≤n≤20000,1≤m≤50,1≤C≤2000)。对于满足(2≤i≤n)的整数(i,1≤F_i<i。1≤A,B≤2^{31}-1,1≤Q≤10000)

Output

包括一个非负整数,表示有多少种放置的方案.

Sample Input

10 5 1 2 10
1 1 3 3 4 4 6 6 9
4
1 6 3
1 9 1
0 1
1 1 1

Sample Output

11
9
12

个人觉得这道题和树形(dp)并没有什么关系。。。

比较显然的就是这题的暴力(dp),我们只需要知道题目给出的(T_{i,j})就可以进行背包的转移了。

题目中的多个矿点的抉择,我们就是利用背包的转移方式进行转移即可。

题目给出了两个限制条件。

1.子树内。

这个我们可以直接暴力(m^2)合并两个矿点,(dfs)序将其变成一个区间,暴力合并(L[x]-R[x])利用合并完的(dp)进行(dp)即可。

2.有一条链。

那个唯一剩下的链我们可以直接对于(Fa[u]-v)中所有的矿点取一个(max)

现在最大的问题就是这是一个动态的问题,那么我们就可以直接用动态树上问题的基本数据结构-树链剖分。

我们将树进行树剖,对于子树的一段区间我们维护合并后的(dp),这个我们可以利用线段数维护。

然后,对于剩下的一条链,我们可以跳重链取一个(max),最后将其和子树的区间进行合并即可。

时间复杂度为预处理复杂度(O(n*log_n*m^2))+单次复杂度(O(m^2*log_n)≈)(O(n*log_n*m^2))

include <bits/stdc++.h>
 
using namespace std;
 
#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
 
inline int Read(void) {
    int res=0,f=1;
    char c;
    while(c=getchar(),c<48||c>57)if(c=='-')f=0;
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>=48&&c<=57);
    return f?res:-res;
}
 
template<class T>inline bool Min(T &a, T const&b) {
    return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
    return a<b?a=b,1:0;
}
const int N=2e4+5,M=2e4+5,X=65536,Y=2147483647;
 
bool MOP1;
 
int n,m,A,B,Q;
 
int us[55],val[N][55];
 
inline int Function(void) {
    A=((A^B)+(B/X)+(B*X))&Y;
    B=((A^B)+(A/X)+(A*X))&Y;
    return (A^B)%Q;
}
 
struct node {
    int dp[55];
    void clear(void) {
        clr(dp,0);
    }
    inline node operator+(node _)const {
        node res;
        res.clear();
        rep(i,0,m)res.dp[i]=max(dp[i],_.dp[i]);
        return res;
    }
    inline node operator*(node _)const {
        node res;
        res.clear();
        rep(i,0,m)rep(j,0,m)if(i+j<=m)Max(res.dp[i+j],_.dp[i]+dp[j]);
        return res;
    }
} E[N];
 
struct Link_list {
    int Tot,Head[N],to[M<<1],Nxt[M<<1];
    inline void clear(void) {
        Tot=0,clr(Head,0);
    }
    inline void AddEdgepair(int a,int b) {
        to[++Tot]=b,Nxt[Tot]=Head[a],Head[a]=Tot;
        to[++Tot]=a,Nxt[Tot]=Head[b],Head[b]=Tot;
    }
} G;
 
int Fa[N],dep[N],Sz[N],son[N];
void dfs1(int x,int pre) {
    Sz[x]=1,Fa[x]=pre,dep[x]=dep[pre]+1;
    erep(i,G,x) {
        int y=G.to[i];
        if(y==pre)continue;
        dfs1(y,x),Sz[x]+=Sz[y];
        (Sz[y]>Sz[son[x]])&&(son[x]=y);
    }
}
 
int L[N],R[N],top[N],Id[N],cnt;
void dfs2(int x,int tp) {
    top[x]=tp,L[x]=++cnt;
    Id[cnt]=x;
    if(son[x])dfs2(son[x],tp);
    erep(i,G,x) {
        int y=G.to[i];
        if(y==Fa[x]||y==son[x])continue;
        dfs2(y,y);
    }
    R[x]=cnt;
}
 
struct Seg {
    node Tr1[N<<2],Tr2[N<<2];
    inline void up(int num) {
        Tr1[num]=Tr1[num<<1]*Tr1[num<<1|1];
        Tr2[num]=Tr2[num<<1]+Tr2[num<<1|1];
    }
    void build(int L,int R,int num) {
        if(L==R) {
            Tr1[num]=Tr2[num]=E[Id[L]];
            return;
        }
        int mid=(L+R)>>1;
        build(L,mid,num<<1);
        build(mid+1,R,num<<1|1);
        up(num);
    }
    void update(int L,int R,int num,int op,node x) {
        if(L==R) {
            Tr1[num]=Tr2[num]=x;
            return;
        }
        int mid=(L+R)>>1;
        if(op<=mid)update(L,mid,num<<1,op,x);
        else update(mid+1,R,num<<1|1,op,x);
        up(num);
    }
    node query1(int L,int R,int num,int l,int r) {
        if(L==l&&R==r)return Tr1[num];
        int mid=(L+R)>>1;
        if(r<=mid)return query1(L,mid,num<<1,l,r);
        else if(l>mid)return query1(mid+1,R,num<<1|1,l,r);
        return query1(L,mid,num<<1,l,mid)*query1(mid+1,R,num<<1|1,mid+1,r);
    }
    node query2(int L,int R,int num,int l,int r) {
        if(L==l&&R==r)return Tr2[num];
        int mid=(L+R)>>1;
        if(r<=mid)return query2(L,mid,num<<1,l,r);
        else if(l>mid)return query2(mid+1,R,num<<1|1,l,r);
        return query2(L,mid,num<<1,l,mid)+query2(mid+1,R,num<<1|1,mid+1,r);
    }
} tr;
 
bool MOP2;
 
void _main(void) {
    n=Read(),m=Read(),A=Read(),B=Read(),Q=Read();
    rep(i,1,n) {
        rep(j,1,m)us[j]=Function();
        sort(us+1,us+m+1);
        E[i].clear();
        rep(j,1,m)E[i].dp[j]=us[j];
    }
    rep(i,2,n) {
        int F=Read();
        G.AddEdgepair(F,i);
    }
    dfs1(1,-1),dfs2(1,1);
    tr.build(1,n,1);
    int C=Read();
    rep(i,1,C) {
        int op=Read();
        if(!op) {
            int p=Read();
            rep(j,1,m)us[j]=Function();
            sort(us+1,us+m+1);
            node Now;
            Now.clear();
            rep(j,1,m)Now.dp[j]=us[j];
            tr.update(1,n,1,L[p],Now);
        } else {
            int u=Read(),v=Read(),Ans=0;
            node L1=tr.query1(1,n,1,L[u],R[u]),R1;
            R1.clear();
            if(u!=v) {
                int x=Fa[u],y=v;
                while(top[x]!=top[y]) {
                    R1=R1+tr.query2(1,n,1,L[top[x]],L[x]);
                    x=Fa[top[x]];
                }
                R1=R1+tr.query2(1,n,1,L[y],L[x]);
            }
            L1=L1*R1;
            printf("%lld
",L1.dp[m]);
        }
    }
}
 
signed main() {
    _main();
    return 0;
}
原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11488864.html