2019 HDU 多校三 Game【博弈+莫队】

传送门

首先就给我们一个玩游戏的策略,很明显知道 SG(x)=x ,想要 Alice 赢,区间SG(x)异或和不为0,我们可以直接处理前缀异或和,然后询问区间不同的异或对,典型的带修莫队,注意细节就可以了。注意答案会爆 int 。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
///SG(x)=x;
int num[maxn], a[maxn];
int cnt[maxn * 20], len;
ll sum, ans[maxn];
int pos[maxn], base;
int cntq, cntc;
struct nodeQ {
    int l, r;   ///查询区间
    int t;      ///查询前修改的次数
    int id;     ///询问编号
} Q[maxn];
int C[maxn];    //改变位置
inline bool cmp(nodeQ a, nodeQ b) {
    if (pos[a.l] == pos[b.l]) {
        if (pos[a.r] == pos[b.r])
            return a.t < b.t;
        return a.r < b.r;
    }
    return a.l < b.l;
}
void add(int x) {
    len++, cnt[a[x]]++;
    sum = sum + len - cnt[a[x]];
}
void del(int x) {
    sum = sum - (len - cnt[a[x]]);
    len--, cnt[a[x]]--;
}
void work(int t, int i) {
    ///交换 pos 和 pos+1 ,只会改变 pos这个位置的前缀异或和
    if (Q[i].l <= C[t] && C[t] <= Q[i].r) {
        ll x = a[C[t]];
        ll y = a[C[t] - 1] ^num[C[t] + 1];
        sum = sum - (len - cnt[x]);
        len--, cnt[x]--;
        len++, cnt[y]++;
        sum = sum + len - cnt[y];
    }
    a[C[t]] = a[C[t] - 1] ^ num[C[t] + 1];
    swap(num[C[t]], num[C[t] + 1]);
}
void Moqueue() {
    int l = 0, r = -1, t = 0;
    for (int i = 1; i <= cntq; i++) {
        while (l < Q[i].l) del(l++);
        while (l > Q[i].l) add(--l);
        while (r < Q[i].r) add(++r);
        while (r > Q[i].r) del(r--);
        while (t > Q[i].t) work(t--, i);
        while (t < Q[i].t) work(++t, i);
        ans[Q[i].id] = sum;
    }
    for (int i = 1; i <= cntq; i++)
        printf("%lld\n", ans[i]);
}
void init() {
    len = sum = cntq = cntc = 0;
    memset(cnt, 0, sizeof(cnt));
}
int main() {
    int n, m;
    while (scanf("%d %d", &n, &m) != EOF) {
        init();
        base = pow(n, 0.6666666666);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &num[i]);
            a[i] = num[i] ^ a[i - 1];
            pos[i] = i / base + 1;
        }
        int op, l, r, s;
        for (int i = 1; i <= m; i++) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d %d", &l, &r);
                cntq++;
                Q[cntq] = nodeQ{l - 1, r, cntc, cntq};
            } else {
                scanf("%d", &s);
                cntc++;
                C[cntc] = s;
            }
        }
        sort(Q + 1, Q + 1 + cntq, cmp);
        Moqueue();
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值