题解:P12539 [XJTUPC 2025] 结束乐队

· · 题解

根号连接大脑,分块代替思考。

这道题可以直接用分块创过去。

首先你注意到 k \le 10^5

好的,我们可以开始根号了。

我们直接考虑下面这个更强的问题(保证是一个排列):

  1. 区间 \operatorname{mex}
  2. 交换俩个数(单点修改)。

这有一个很简单的分块做法。

序列分块,值域分块。

维护:

$col_{i,j}$ 表示第序列 $1 \sim i$ 块内在数值为 $j$ 的数的数量。 查询: 先跳值域整块,再跳值域散块。 序列散块暴力,就不多说了。 修改: 由于你维护的是块的前缀和,无论是 $block\_col_{i,j}$ 还是 $col_{i,j}$ 都只有 $\sqrt n$ 个要修改的地方,暴力修改即可。 但是,$n = 5\times 10^5$ , $col_{i,j}$ 的空间是 $n \sqrt n$ 的,初始化也是 $n\sqrt n$ 的,过不去(其实可以用 bitset) 所以你考虑跳值域散块的时候不用 $col_{i,j}$ 了,你发现只要 $l \le pos_x \le r$,$x$ 就在 $[l , r]$ 中( $pos_i$ 表示 $i$ 这个值的出现位置)。 所以你维护一下 $pos_i$ 就行了。 所以根本用不到交换的俩个值的性质,就做完了。 总复杂度 $O(n + k\sqrt n)$ 最慢点 313 ms ,没卡常。 ```cpp #include<bits/stdc++.h> #define f(i , l , r) for(int i = (l);i <= (r);++ i) #define d(i , l , r) for(int i = (r);i >= (l);-- i) #define pii pair<int,int> #define pb push_back #define fi first #define sc second #define lowbit(x) ((x)&-(x)) #define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout) using namespace std; const int N = 5e5 + 10 , B = 1024;//1024位运算,方便卡常 int n , k , a[N] , col[N/B+10][N/B+10] , bl[N] , L[N] , R[N] , pos[N] , t[N]; void change(int u,int v){ f(i , bl[u] , bl[n])col[i][bl[a[u]]] -- , col[i][bl[a[v]]] ++; f(i , bl[v] , bl[n])col[i][bl[a[v]]] -- , col[i][bl[a[u]]] ++; swap(a[u] , a[v]) , swap(pos[a[v]] , pos[a[u]]); } signed main(){ ios_base::sync_with_stdio(0); cin.tie(0) , cout.tie(0); cin >> n; f(i , 1 , n)cin >> a[i] , pos[a[i]] = i; f(i , 1 , n)bl[i] = (i - 1) / B + 1 , R[bl[i]] = i , L[bl[i]] = R[bl[i]-1] + 1; f(i , 1 , bl[n]){ f(j , 1 , bl[n])col[i][j] = col[i-1][j]; f(j , L[i] , R[i])col[i][bl[a[j]]] ++; } cin >> k; // cerr << "ok\n"; f(i , 1 , k){ int l , r , p = 1; cin >> l >> r; if(bl[l] == bl[r]){ f(j , 1 , bl[n])t[j] = 0; f(j , l , r)t[bl[a[j]]] ++; // int p = 1; while(p < bl[n] && t[p] == R[p] - L[p] + 1)p ++; p = L[p]; while(l <= pos[p] && pos[p] <= r)p ++; } else { int rb = bl[r] , lb = bl[l]; f(j , 1 , bl[n])t[j] = col[rb-1][j] - col[lb][j]; f(j , l , R[lb])t[bl[a[j]]] ++; f(j , L[rb] , r)t[bl[a[j]]] ++; // int p = 1; while(p < bl[n] && t[p] == R[p] - L[p] + 1)p ++; // cerr << p << "\n"; p = L[p]; while(l <= pos[p] && pos[p] <= r)p ++; } if(p >= n)cout << "peace\n"; else cout << p << "\n" , change(pos[p] , pos[p + 1]); // f(j , 1 , n)cout << a[j] << " ";cout << "\n"; } } ```