zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    Java设计模式知识整理
    Java单例实现及分析
    Java开源框架知识整理
    JavaJ2EE相关知识整理
    数据库相关知识整理
    JavaJDK8新特性相关知识整理
    Java并发编程相关知识整理
    Java集合框架相关知识整理
    Java虚拟机JVM相关知识整理
    若依项目利用nginx实现负载均衡及保持会话
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11488864.html
Copyright © 2011-2022 走看看