这次怎么打成区了。

赛后复盘

首先我的情况应该是 80% 做 E,60% 做 F。

赛时 30min 写完前四题后第三题并没有过。看到 E 是期望,F 是串串,认为磕期望比磕 F 好。当时以为做一个题再调 C 是绝对不劣的,所以我就把 C 扔开了。

随后 21:10 时写完了 E,但是调题的本事确实不是很强。看了一眼 F,发现会了。调 E?还是写 F?其实已经看见群里说 G<F<E 及 D<C 了,但是(不知道是不是因为集训刚学)死都要做出来 E。

拍了 15min 后被高人指导了。说 set 会 TLE,那我改成 vector 呗。

拜谢 HI 未来队长 xtk,我宣布我这次打爆是因为你带歪榜了!!

C 题解

直接暴力加一堆玄学优化显然是过不去的,不知道为什么有素质低的人一直在误导。

先来了解异或的一个性质,\(x\oplus y=z\),则 \(z\oplus y=x,z\oplus x=y\),其中 \(\oplus\) 是按位异或。所以操作一等价于让 \(ans\) 变成 \(ans\oplus a_i\oplus (a_i-1)\),然后再让 \(a_i\leftarrow a_i-1\)

我们发现操作二只有 \(\ge 1\) 的数才会被操作到。我们维护一个数据结构,使得一个数 \(\ge 1\) 就在里面,然后每次操作就遍历一遍这个数据结构,如果变成 \(0\) 了就弹出去。set 确实能做,但是有 \(O(N)\) 的 vector 神力。

这里重点说一下如何去避免删了 \(a_i\) 后迭代器跑不到下一个数的问题。再定义一个 vector,然后把保留的放到第二个里,最后再交换即可。

时间复杂度证明不显然。我们发现每个数在 vector 被遍历的次数等价于它被操作一加一的次数,所以时间复杂度是 \(O(N+Q)\)。这里插一嘴,set 的时间复杂度是 \(O(N\log N+Q\log Q)\)

代码如下。

#include<iostream>
#include<vector>
using namespace std;
int read() {
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int N = 5e5 + 10;
int n,q;
int a[N];
vector<int> v,tmp;
bool vis[N];
int sxor;
int main() {
    n = read(),q = read();
    for (int i = 1; i <= q; i++) {
        int op = read();
        if (op == 1) {
            int x = read();
            sxor ^= a[x];
            a[x]++;
            sxor ^= a[x];
            if (a[x] == 1) {
                v.push_back(x);
            }
        }
        else {
            sxor = 0;
            while (v.size()) {
                int x = v.back();
                v.pop_back();
                a[x]--;
                if (a[x]) {
                    tmp.push_back(x);
                }
                sxor ^= a[x];
            }
            swap(v,tmp);
        }
        cout << sxor << "\n";
    }
    return 0;
}
posted on 2026-08-09 07:45  Pure_ManaWing  阅读(72)  评论(0)    收藏  举报