luogu P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I
https://www.luogu.com.cn/problem/P5046
区间逆序对,强制在线,吼哇
如果离线就是二次离线莫队
思路倒是不难,就是卡常严重QWQ
不过确实是我有个地方写丑了
预处理几个东西
- a n s L [ i ] [ j ] 表 示 [ L [ i ] , j ] 的 答 案 , ( 第 i 块 的 左 端 点 到 j 的 答 案 ) ansL[i][j]表示 [L[i],j]的答案,(第i块的左端点到j的答案) ansL[i][j]表示[L[i],j]的答案,(第i块的左端点到j的答案)
- a n s R [ i ] [ j ] 表 示 [ j , R [ i ] ] 的 答 案 ansR[i][j]表示[j,R[i]]的答案 ansR[i][j]表示[j,R[i]]的答案
如果不考虑左右散块之间的贡献,显然可以得到是
加起来减去中间的(红+蓝-黑)
然后考虑散块怎么做
很简单,直接预先排好序,归并起来即可
代码实现不算复杂,注意卡常(交前洗把脸)
code:
#include<bits/stdc++.h>
#define N 100005
#define M 325
#define ll long long
using namespace std;
int read() {
int x = 0;
char ch = getchar();
for(; ch < '0' || ch > '9'; ) ch = getchar();
for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - 48), ch = getchar();
return x;
}
struct A {
int x, id;
} b[N];
int cmp(A x, A y) {
return x.x < y.x;
}
int x[N], y[N], cx, cy, a[N], pre[N], suf[N], s1[M][N], s2[M][N], n, m, blo, bel[N], sp[N], gs[N];
#define lowbit(x) (x & -x)
int t[N];
void update(int x, int y) {
for(; x <= n; x += lowbit(x)) t[x] += y;
}
int query(int x) {
int ret = 0;
for(; x; x -= lowbit(x)) ret += t[x];
return ret;
}
ll *ansL[M], *ansR[M], B[N * M * 3 / 2], *now = B;
int merge() {
int i = 1, j = 1, ret = 0;
for(; i <= cx && j <= cy; ) {
if(x[i] < y[j]) i ++;
else ret += cx - i + 1, j ++;
}
return ret;
}
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i ++) a[i] = read(), b[i].x = a[i], b[i].id = i;
blo = min(550, n);
//blo = sqrt(n) + 1;
for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / blo + 1;
for(int id = 1; id <= bel[n]; id ++) {
int l = (id - 1) * blo + 1, r = min(id * blo, n);
sort(b + l, b + r + 1, cmp);
for(int i = l; i <= r; i ++) update(a[i], 1), pre[i] = i - l + 1 - query(a[i]);
for(int i = l; i <= r; i ++) update(a[i], - 1);
for(int i = r; i >= l; i --) update(a[i], 1), suf[i] = query(a[i] - 1);
for(int i = l; i <= r; i ++) update(a[i], - 1);
sp[l] = pre[l];
for(int i = l + 1; i <= r; i ++) sp[i] = sp[i - 1] + pre[i];
}
for(int i = 1; i <= bel[n]; i ++) {
int l = (i - 1) * blo + 1, r = min(i * blo, n);
for(int j = l; j <= r; j ++) gs[a[j]] ++;
for(int j = 1; j <= n; j ++) s1[i][j] = s1[i][j - 1] + gs[j];
for(int j = n; j >= 1; j --) s2[i][j] = s2[i][j + 1] + gs[j];
}
for(int i = 1; i <= bel[n]; i ++) {
int l = (i - 1) * blo + 1, r = min(i * blo, n);
//ansL[i].resize(n - l + 2);
ansL[i] = now; now += n - l + 2;
int py = l - 1;
for(int j = l; j <= n; j ++) ansL[i][j - py] = ansL[i][j - 1 - py] + (s2[bel[j] - 1][a[j] + 1] - s2[i - 1][a[j] + 1]) + pre[j];
//ansR[i].resize(r + 2);
ansR[i] = now; now += r + 2;
for(int j = r; j >= 1; j --) ansR[i][j] = ansR[i][j + 1] + (s1[i][a[j] - 1] - s1[bel[j]][a[j] - 1]) + suf[j];
}
ll lst = 0;
for(; m --; ) {
int l, r;
l = read(), r = read();
l ^= lst, r ^= lst; if(l > r) swap(l, r); lst = 0;
ll s = 0;
cx = cy = 0;
int L = (bel[l] - 1) * blo + 1, R = min(n, bel[r] * blo);
if(bel[l] == bel[r]) {
for(int i = L; i <= R; i ++) {
if(b[i].id < l) lst -= s;
s += (l <= b[i].id && b[i].id <= r);
}
lst += sp[r] - (l == L? 0 : sp[l - 1]);
printf("%lld\n",lst);
} else {
int py = bel[l] * blo;
lst = ansL[bel[l] + 1][r - py] + ansR[bel[r] - 1][l] - ansL[bel[l] + 1][(bel[r] - 1) * blo - py];
int szl = bel[l] * blo;
for(int i = L, j = (bel[r] - 1) * blo + 1; j <= R && i <= szl; j ++) {
for( ; b[i].x < b[j].x && i <= szl; ) s += b[i].id >= l, i ++;
lst += (b[j].id <= r) * (szl - l + 1 - s);
}
// for(int i = L; i <= bel[l] * blo; i ++) if(b[i].id >= l) x[++ cx] = b[i].x;
// for(int i = (bel[r] - 1) * blo + 1; i <= R; i ++) if(b[i].id <= r) y[++ cy] = b[i].x;
//lst += merge();
printf("%lld\n", lst);
}
}
return 0;
}