• Codedforces 1076G Array Game 线段树


    题意

    现在cf上看题意真nm麻烦,有道网页翻译和谷歌翻译鬼畜的一匹
    两个人在玩一个游戏。
    有一个有(n)个数序列(B),一开始有一个棋子在(B)的第一个位置。
    双方轮流操作,第一次操作前将(B_1-1)
    然后每次操作,你可以把棋子移到一个位置(jin[i,min(i+m,n)])(B_j>0),然后将(B_j-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);
    	}
    } 
    
  • 相关阅读:
    数据结构进阶——线段树
    基本数据结构—Hash哈希
    NOIP2013提高组 day2 2019.7.15
    基本算法——归并排序
    基本数据结构—Trie
    NOIP 2011 提高组 Day2 校模拟 7.11
    Noip2014提高组真题Day1,2 校模拟7.7
    NOIP2015 提高组 day1 7.8校模拟
    NOIP2008 提高组 6.9校模拟
    STL-#include<set>
  • 原文地址:https://www.cnblogs.com/zykykyk/p/10089236.html
Copyright © 2020-2023  润新知