1. 程式人生 > >Codedforces 1076G Array Game 線段樹

Codedforces 1076G Array Game 線段樹

題意

現在cf上看題意真nm麻煩,有道網頁翻譯和谷歌翻譯鬼畜的一匹
兩個人在玩一個遊戲。
有一個有\(n\)個數序列\(B\),一開始有一個棋子在\(B\)的第一個位置。
雙方輪流操作,第一次操作前將\(B_1-1\)
然後每次操作,你可以把棋子移到\([i,min(i+m,n)]\)\(B_i>0\)的一個位置,並將\(B_i-1\),假設雙方都採用最優策略,誰先不能操作誰輸。
然後你的將要解決的問題是:
給出一個長度為\(n\)的序列\(A\)\(m\),以及詢問數\(q\)
詢問有兩種,一種是區間加,另一種是詢問\(A\)序列的一個區間,以這段區間作為序列\(B\)進行上面的遊戲,問先手還是後手贏。

\(n.q<=2*10^5 m<=5\)

Solution

先考慮給出一個序列\(B\),怎麼判斷是先手贏還是後手贏。
\(f_i\)為當一個玩家第一次選到第\(i\)個位置時他會不會贏。
如果\([i+1,i+m]\)裡有一個先手必勝,那麼這個位置就是先手必敗,\(f_i=0\)
否則就要看當前位置上的值的奇偶性了,冷靜分析下不難想到這時當\(A_i\)為偶數時\(f_i=0\),為奇數時\(f_i=1\)
所以當前\(f_i\)的值我們可以從\(f_j (j \in [i+1,i+m])\)中推出。
然後考慮這東西怎麼維護。
發現\(m\)很小,所以我們大力把後\(m\)

\(f_j\)壓起來。
用線段樹來維護這個東西,每個節點維護當這個區間的右端點右邊的\(m\)個位置的\(f_j\)壓起來為\(k\)時,這個區間左端點右邊的\(m\)\(f_j\)壓起來的值。
合併的時候\(xjb\)的轉移下就行了。
修改的話,不難發現當\(d\)為偶數並沒有什麼用。
我們可以把當區間所有數^1的值也算出來,那麼修改就只要\(swap\)一下就行了。
感覺\(NOIP\)後搞文化課導致降智嚴重啊...連這樣的題都要看題解了...\(QAQ\)

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-'){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
const int N = 3e5+10;
int n,m,q,p,a[N];
struct node{
    int f[32];
    inline node operator + (const node &b)const{
        node ans;
        For(i,0,p) ans.f[i]=f[b.f[i]];
        return ans;
    }
};
inline node New(int x){
    node ans;ans.f[0]=x;
    For(i,1,p) ans.f[i]=i<<1&p;
    return ans;
}
struct SegMent_Tree{
    node v[N<<2][2];
    bool lazy[N<<2];
    inline void push_up(int u){For(i,0,1) v[u][i]=v[u<<1][i]+v[u<<1^1][i];}
    inline void Build(int u,int l,int r){
        if (l==r){v[u][0]=New(a[l]),v[u][1]=New(a[l]^1);return;}
        int mid=l+r>>1;Build(u<<1,l,mid),Build(u<<1^1,mid+1,r);
        push_up(u);
    }
    inline void push_down(int u){
        if (!lazy[u]) return;
        swap(v[u<<1][0],v[u<<1][1]),swap(v[u<<1^1][0],v[u<<1^1][1]);
        lazy[u<<1]^=1,lazy[u<<1^1]^=1,lazy[u]=0;
    }
    inline void update(int u,int l,int r,int ql,int qr){
        if (l>=ql&&r<=qr){lazy[u]^=1,swap(v[u][0],v[u][1]);return;}
        int mid=l+r>>1;push_down(u);
        if (qr<=mid) update(u<<1,l,mid,ql,qr);
        else if (ql>mid) update(u<<1^1,mid+1,r,ql,qr);
        else update(u<<1,l,mid,ql,qr),update(u<<1^1,mid+1,r,ql,qr);
        push_up(u);
    }
    inline node Query(int u,int l,int r,int ql,int qr){
        if (l>=ql&&r<=qr) return v[u][0];
        int mid=l+r>>1;push_down(u);
        if (qr<=mid) return Query(u<<1,l,mid,ql,qr);
        else if (ql>mid) return Query(u<<1^1,mid+1,r,ql,qr);
        else return Query(u<<1,l,mid,ql,qr)+Query(u<<1^1,mid+1,r,ql,qr);
    }
}t;
int main(){
    n=read(),m=read(),q=read(),p=(1<<m)-1;
    For(i,1,n) a[i]=read()&1;
    t.Build(1,1,n);
    while (q--){
        int opt=read(),l=read(),r=read();
        if (opt==2) puts(t.Query(1,1,n,l,r).f[0]&1?"2":"1");
            else if (read()&1) t.update(1,1,n,l,r);
    }
}