Codedforces 1076G Array Game 線段樹
阿新 • • 發佈:2018-12-08
題意
現在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\)
用線段樹來維護這個東西,每個節點維護當這個區間的右端點右邊的\(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); } }