【HMOI】小C的填数游戏 DP+线段树维护

  【题目描述】

    一个长为n的序列,每个元素有一个a[i],b[i],a[i]为0||1,每个点和他相邻的两个点分别有两条边,权值为cost1[i],cost2[i],对于每个区间l,r,我们可以给每一个数一个c[i]值,c[i]=0||1,使得Σ(b[j]*(a[j]^c[j]))+cost1[j]*(c[j]^c[j+1])+cost2[j]*(c[j]^c[j+2]),j,j+1,j+2在[l,r]内时累加,现在有m次操作:

      M x:将x位置的a[i]^=1;

      Q l r:询问区间l,r的答案。

  首先假设询问的只是一个区间,那么我们可以比较容易的用dp来求解w[i][s]表示到第i位的时候,后两位选的s的最小值,那么我们可以转移到w[i+1][ss]。这样就可以得到答案了。

   但是现在我们支持区间询问和修改,所以我们用线段树来维护,每个节点记录w[s],s为这个区间左面两个点c[i]的选取方法和右面两个点的选取方法,那么只要我们可以维护线段树每个节点的w[i],我们就可以解决这个问题了。

  对于合并操作比较简单,只需要枚举两个节点的s,然后更新的ss就可以了。

  反思:一个节点的情况需要特殊处理,开始没注意到这个,后来改了半天,合并的时候还分了三种情况讨论= =。

     还需要开LL,设inf的时候设的是#define inf (1<<60) 结果改了半天= =

     评测数据的5号评测点少了一个操作,然后我的输出就多了一行= =。

//By BLADEVIL
#include <cstdio>
#include <cstring>
#define min(x,y) (x>y)?y:x;
#define inf (1ll<<60)
#define maxn 30010
#define LL long long

using namespace std;

struct rec {
    int left,right;
    LL key;
    LL w[20];
    rec() {
        left=right=0;
        key=inf;
        for (LL i=0;i<20;i++) w[i]=inf;
    }
}t[maxn<<2];

LL n,m;
LL a[maxn],b[maxn],cost1[maxn],cost2[maxn];
char s[10];

void init(int x) {
    t[x].w[0]=b[t[x].left]*a[t[x].left];
    t[x].w[1]=b[t[x].left]*(a[t[x].left]^1);
    t[x].key=min(t[x].w[0],t[x].w[1]);
}

rec update(rec a,rec b) {
    rec ans;
    ans.left=a.left; ans.right=b.right;
    if ((a.left==a.right)&&(b.left==b.right))
        for (LL s=0;s<4;s++) {
            LL ss=s|(s<<2);
            LL c1=((s&2)==2)?1:0,c2=((s&1)==1)?1:0; 
            //if ((ss==3)&&(a.left==1)) printf("%d %d\n",c1,c2);
            if ((a.w[c1]==inf)||(b.w[c2]==inf)) continue;
            ans.w[ss]=min(ans.w[ss],a.w[c1]+b.w[c2]+(c1^c2)*cost1[a.right]);
            //if ((ss==3)&&(a.left==1)&&(a.right==1)) printf("%d\n",ans.w[ss]);
            ans.key=min(ans.key,ans.w[ss]);
            //if ((a.left==1)&&(a.right==1)) printf("%d %d\n",ans.key,ss);
        } else 
    if (a.left==a.right)
        for (LL s1=0;s1<2;s1++)
            for (LL s2=0;s2<16;s2++) {
                if ((a.w[s1]==inf)||(b.w[s2]==inf)) continue;
                LL s=0;
                s|=s1<<3; s|=(s2&8)>>1; s|=s2&3;
                LL c2=((s2&8)==8)?1:0,c3=((s2&4)==4)?1:0;
                ans.w[s]=min(ans.w[s],a.w[s1]+b.w[s2]+(s1^c2)*cost1[a.left]+(s1^c3)*cost2[a.left]);
                ans.key=min(ans.key,ans.w[s]);
            } else 
    if (b.left==b.right)
        for (LL s1=0;s1<16;s1++)
            for (LL s2=0;s2<2;s2++) {
                if ((a.w[s1]==inf)||(b.w[s2]==inf)) continue;
                LL s=0;
                s|=s2; s|=(s1&1)<<1; s|=s1&12;
                LL c1=((s1&2)==2)?1:0,c2=((s1&1)==1)?1:0;
                ans.w[s]=min(ans.w[s],a.w[s1]+b.w[s2]+(c1^s2)*cost2[a.right-1]+(c2^s2)*cost1[a.right]);
                ans.key=min(ans.key,ans.w[s]);
            } else 
    if ((a.left!=a.right)&&(b.left!=b.right))
        for (LL s1=0;s1<16;s1++) 
            for (LL s2=0;s2<16;s2++) {
                if ((a.w[s1]==inf)||(b.w[s2])==inf) continue;
                LL s=(s1>>2)<<2;
                s|=s2&3;
                LL c1=((s1&2)==2)?1:0,c2=((s1&1)==1)?1:0;
                LL c3=((s2&8)==8)?1:0,c4=((s2&4)==4)?1:0;
                LL Ans=a.w[s1]+b.w[s2];
                Ans+=cost1[a.right]*(c2^c3)+cost2[a.right]*(c2^c4)+cost2[a.right-1]*(c1^c3);
                ans.w[s]=min(ans.w[s],Ans);
                ans.key=min(ans.key,ans.w[s]);
            }
    return ans;
}

void build(int x,int l,int r) {
    t[x].left=l; t[x].right=r;
    if (t[x].left==t[x].right) {
        init(x);
        return ;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid); build((x<<1)+1,mid+1,r);
    t[x]=update(t[x<<1],t[(x<<1)+1]);
}

rec query(int x,int l,int r) {
    if ((t[x].left==l)&&(t[x].right==r)) return t[x];
    int mid=t[x].left+t[x].right>>1;
    if (mid>=r) return query(x<<1,l,r); else 
    if (mid<l) return query((x<<1)+1,l,r); else 
        return update(query(x<<1,l,mid),query((x<<1)+1,mid+1,r));
}

void change(int x,int y) {
    if (t[x].left==t[x].right) {
        init(x);
        return ;
    }
    LL mid=t[x].left+t[x].right>>1;
    if (y>mid) change((x<<1)+1,y); else change(x<<1,y);
    t[x]=update(t[x<<1],t[(x<<1)+1]);
}

int main() {
    freopen("game.in","r",stdin); freopen("game.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for (LL i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (LL i=1;i<=n;i++) scanf("%lld",&b[i]);
    for (LL i=1;i<n;i++) scanf("%lld",&cost1[i]);
    for (LL i=1;i<n-1;i++) scanf("%lld",&cost2[i]);
    build(1,1,n);
    /*
    for (LL s=0;s<16;s++) printf("%d %d\n",s,query(1,1,3).w[s]);
    return 0;
    */
    //printf("%d\n",query(1,2,4).key); return 0;
    while (m--) {
        scanf("%s",s);    
        LL x,y;
        if (s[0]=='Q') {
            scanf("%lld%lld",&x,&y);
            printf("%lld\n",query(1,x,y).key);
        } else {
            scanf("%lld",&x);
            a[x]^=1;
            change(1,x);
        }
    }
    //for (LL s=0;s<16;s++) printf("%d %d\n",s,query(1,1,4).w[s]);
    fclose(stdin); fclose(stdout);
    return 0;
}

 

posted on 2014-03-29 10:53  BLADEVIL  阅读(10553)  评论(0编辑  收藏  举报