Codeforces 1076G Array Game 博弈 + 线段树 (看题解)

Array Game

考虑最裸的dp去求胜负态。

dp[ i ] 从后面的 m 个状态转移过来。

我们考虑如何用线段树维护, T[ i ][ mask ] 表示 i 这段区间如果后面接的m位是mask使时开头m位的mask,

对于修改的话只要维护一个反过来的T2就可以了。

感觉是可以想出来的题, 为什么没想出来啊啊啊。

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N = (int)2e5 + 7;

int n, m, q, bit, ans, a[N];

int lazy[N << 2];
vector<int> T[N << 2], T2[N << 2];

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1

inline void pull(int rt) {
    for(int i = 0; i < T[rt].size(); i++) {
        T[rt][i] = T[rt << 1][T[rt << 1 | 1][i]];
        T2[rt][i] = T2[rt << 1][T2[rt << 1 | 1][i]];
    }
}

inline void push(int rt) {
    if(lazy[rt]) {
        swap(T[rt << 1], T2[rt << 1]);
        swap(T[rt << 1 | 1], T2[rt << 1 | 1]);
        lazy[rt << 1] ^= 1;
        lazy[rt << 1 | 1] ^= 1;
        lazy[rt] = 0;
    }
}

void build(int l, int r, int rt) {
    T[rt].resize(1 << m, 0);
    T2[rt].resize(1 << m, 0);
    if(l == r) {
        for(int i = 0; i < T[rt].size(); i++) {
            if(i != ((1 << m) - 1)) T[rt][i] = (i >> 1) | bit, T2[rt][i] = (i >> 1) | bit;
            else if(a[l]) T[rt][i] = (i >> 1), T2[rt][i] = (i >> 1) | bit;
            else T[rt][i] = (i >> 1) | bit, T2[rt][i] = (i >> 1);
        }
        return;
    }
    int mid = l + r >> 1;
    build(lson); build(rson);
    pull(rt);
}

void update(int L, int R, int l, int r, int rt) {
    if(R < l || r < L || R < L) return;
    if(L <= l && r <= R) {
        swap(T[rt], T2[rt]);
        lazy[rt] ^= 1;
        return;
    }
    push(rt);
    int mid = l + r >> 1;
    update(L, R, lson);
    update(L, R, rson);
    pull(rt);
}

void query(int L, int R, int l, int r, int rt) {
    if(R < l || r < L || R < L) return;
    if(L <= l && r <= R) {
        ans = T[rt][ans];
        return;
    }
    push(rt);
    int mid = l + r >> 1;
    query(L, R, rson); query(L, R, lson);
}

int main() {
    scanf("%d%d%d", &n, &m, &q);
    bit = 1 << m - 1;
    for(int i = 1; i <= n; i++) {
        LL x; scanf("%lld", &x);
        a[i] = x & 1;
    }
    build(1, n, 1);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op == 1) {
            int l, r; LL x;
            scanf("%d%d%lld", &l, &r, &x);
            if(x & 1) update(l, r, 1, n, 1);
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            ans = (1 << m) - 1;
            query(l, r, 1, n, 1);
            if(ans & bit) puts("1");
            else puts("2");
        }
    }
    return 0;
}

/**
**/

原文地址:https://www.cnblogs.com/CJLHY/p/11722723.html

时间: 2024-10-03 06:48:58

Codeforces 1076G Array Game 博弈 + 线段树 (看题解)的相关文章

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

Codeforces 283E Cow Tennis Tournament 线段树 (看题解)

Cow Tennis Tournament 感觉这题的难点在于想到求违反条件的三元组.. 为什么在自己想的时候没有想到求反面呢!!!! 违反的三元组肯定存在一个人能打败其他两个人, 扫描的过程中用线段树维护一下就好了. 反思: 计数问题: 正难则反 正难则反 正难则反 !!!! #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi

CodeForces 600E Lomsat gelral(线段树合并)

题目链接:http://codeforces.com/problemset/problem/600/E You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in

codeforces 374D. Inna and Sequence 线段树

题目链接 给m个数, n个操作, 一个数列, 初始为空.一共有3种操作, 在数列末尾加0, 加1, 或删除位置为a[i]的数, a[i]为初始给的m个数, 如果a[i]大于数列长度, 那么什么也不发生. 求最后的数列. 用线段树, 因为最多只有n个操作, 也就是说最后的01串最大长度为n, 那么可以用一个变量now表示当前插入的话应该插入到哪个位置, 每插入一个数, now就加1,并且now最终不会超过n. 删除操作的话, 递归的进行, 如果sum[rt<<1]大于要删除的下标那么就往左儿子递

codeforces 242E. XOR on Segment 线段树

题目链接 给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x. 异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵线段树就可以. 每一次异或, 对于给定的x, 如果x的第i位是1, 那么就将第i棵线段树在给定的区间内0,1翻转, 这是很基础的操作. 对于区间求和操作, 我们可以求出给定的区间, 从高位到低位, 每一位依次有多少个1, 然后就可以直接求出来, 感觉不好表达....具体看代码. 1 #include

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing

Codeforces 834D The Bakery - 动态规划 - 线段树

Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredients and a wonder-oven which can bake several types of cakes, and opened the bakery. Soon the expenses started to overcome the income, so Slastyona decid