【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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM