dtoi4649 光明

时间:2020-02-01 01:12:06   收藏:0   阅读:90

题意:

     现在有 n 块水晶石板形成一个序列,每块水晶石板有一个权值 。

第 i 块水晶石板的大小是 ai?bi?的,也就是有 ai?bi? 个格子。

A和B要拿这些石板玩游戏。

每次玩游戏,A都会先选择一个区间 [l,r],B只能选择这个区间的一个子区间。

对于这个子区间中的每个石板,A可以任意指定一个点作为起点,B需要从这个起点出发不重不漏地经过每一个格子并回到这个点(每次移动只能向上下左右中的一个方向),那么B可以获得这块石板的权值,否则A获得这块石板的权值。B每次都想最大化自己的得分减去A的得分。注意,B不可以选择一个空集。

现在有 q 次操作,每次操作是三种之一

x a b:修改第 x 块水晶石板的大小为 a*b

2 x w:修改第 x 块水晶石板的权值为 w

3 l r:A和B玩游戏,A选择了区间 [l,r],B需要选择一个 [l,r] 中的子区间,最大化(B的得分-A的得分)

为了避免石板的长或宽为 1 时回到起始点存在问题,始终保证 ai?>1,bi?>1 。

题解:

     首先我们要知道,某一块水晶石板什么时候贡献为w,什么时候贡献为-w。

     只要长或者宽有一个为偶数即可完成这个任务,贡献就为w,否则为-w。如果有一个是偶数,那么我们可以蛇形走位然后再绕回来。(自己画一画就知道了)

     接下来就是动态维护区间最大连续子段和,可以采用线段树维护。这是一个经典问题,我们需要维护左最大,右最大和总的最大值就可以了。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF=1e9;
int n,w[100002],a[100002],b[100002];
typedef struct{
    int lMax,rMax,Max,sum;
}P;
P p[400002],ans1,ans2;
void hb(int root){
    p[root].sum=p[root*2].sum+p[root*2+1].sum;
    p[root].Max=max(max(p[root*2].Max,p[root*2+1].Max),p[root*2].rMax+p[root*2+1].lMax);
    p[root].lMax=max(p[root*2].lMax,p[root*2].sum+p[root*2+1].lMax);
    p[root].rMax=max(p[root*2+1].rMax,p[root*2+1].sum+p[root*2].rMax);
}
void hb2(int root){
    ans2.sum=ans1.sum+p[root].sum;
    ans2.Max=max(max(ans1.Max,p[root].Max),ans1.rMax+p[root].lMax);
    ans2.lMax=max(ans1.lMax,ans1.sum+p[root].lMax);
    ans2.rMax=max(p[root].rMax,p[root].sum+ans1.rMax);
}
void build(int root,int begin,int end){
    if (begin==end)
    {
        if (a[begin]%2==0 || b[begin]%2==0)p[root].Max=p[root].lMax=p[root].rMax=p[root].sum=w[begin];
        else p[root].Max=p[root].lMax=p[root].rMax=p[root].sum=-w[begin];
        return;
    }
    int mid=(begin+end)/2;
    build(root*2,begin,mid);build(root*2+1,mid+1,end);
    hb(root);
}
void gengxin(int root,int begin,int end,int wz,int z){
    if (begin>wz || end<wz)return;
    if (begin==end)
    {
        p[root].Max=p[root].lMax=p[root].rMax=p[root].sum=z;
        return;
    }
    int mid=(begin+end)/2;
    gengxin(root*2,begin,mid,wz,z);gengxin(root*2+1,mid+1,end,wz,z);
    hb(root);
}
void chaxun(int root,int begin,int end,int begin2,int end2){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        ans1=ans2;hb2(root);return;
    }
    int mid=(begin+end)/2;
    chaxun(root*2,begin,mid,begin2,end2);chaxun(root*2+1,mid+1,end,begin2,end2);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",&w[i]);
    for (int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    build(1,1,n);
    int q;scanf("%d",&q);
    while(q--)
    {
        int op;
        scanf("%d",&op);
        if (op==1)
        {
            int x,aa,bb;
            scanf("%d%d%d",&x,&aa,&bb);
            a[x]=aa;b[x]=bb;
            if (a[x]%2 && b[x]%2)gengxin(1,1,n,x,-w[x]);else gengxin(1,1,n,x,w[x]);
        }
        if (op==2)
        {
            int x,ww;
            scanf("%d%d",&x,&ww);
            w[x]=ww;
            if (a[x]%2 && b[x]%2)gengxin(1,1,n,x,-w[x]);else gengxin(1,1,n,x,w[x]);
        }
        if (op==3)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            ans2.sum=0;ans2.lMax=ans2.rMax=ans2.Max=-INF;
            chaxun(1,1,n,l,r);
            printf("%d\n",ans2.Max);
        }
    }
    return 0;
}
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!