题目大意:强制在线区间无修改逆序对。
思路:看到数据范围发现分块是很显然的。预处理了很多东西,比如说每个块里面的逆序对个数,还有f[i][j]表示从第i块到第j块的逆序对个数。如果仅仅处理到这里的话,后面是不太好处理的。我们还需要一个东西,是每个点对每个块的逆序对个数,并取前缀合优化。否则的话就得用主席树来乱搞,那常数
反正总时间复杂度大概是O(n*sqrt(n)*logn) 强行不到O(n^2)
剩下就是小事了, 比如离散话啥的。。
CODE:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 400
#define RANGE 50010
using namespace std;
#define max(a,b) ((a) > (b) ? (a):(b))
struct Block{
int num[MAX],total;
void Add(int x) {
num[++total] = x;
}
}block[MAX];
int cnt,size,blocks,asks;
pair<int,int *> xx[RANGE];
int src[RANGE],t;
int belong[RANGE],_begin[MAX],_end[MAX];
int fenwick[RANGE],v[RANGE],T;
int ans[MAX][MAX],g[RANGE][MAX];
inline void Fix(int x)
{
for(; x; x -= x&-x) {
if(v[x] != T) v[x] = T,fenwick[x] = 0;
++fenwick[x];
}
}
inline int GetSum(int x)
{
int re = 0;
for(; x <= t; x += x&-x) {
if(v[x] != T) v[x] = T,fenwick[x] = 0;
re += fenwick[x];
}
return re;
}
int temp[RANGE];
inline int Calc(int total)
{
++T;
int re = 0;
for(int i = 1; i <= total; ++i) {
re += GetSum(temp[i] + 1);
Fix(temp[i]);
}
return re;
}
int main()
{
cin >> cnt;
size = sqrt(cnt);
for(int i = 1; i <= cnt; ++i) {
scanf("%d",&xx[i].first);
xx[i].second = &src[i];
}
sort(xx + 1,xx + cnt + 1);
for(int i = 1; i <= cnt; ++i) {
if(i == 1 || xx[i].first != xx[i - 1].first)
++t;
*xx[i].second = t;
}
for(int i = 1; i <= cnt; ++i) {
belong[i] = i / size + 1;
blocks = max(blocks,belong[i]);
if(!_begin[belong[i]]) _begin[belong[i]] = i;
if(belong[i] != belong[i - 1]) _end[belong[i] - 1] = i - 1;
}
_end[blocks] = cnt;
for(int i = 1; i <= cnt; ++i)
block[belong[i]].Add(src[i]);
for(int i = 1; i <= blocks; ++i) {
++T;
int inv = 0;
for(int j = i; j <= blocks; ++j) {
for(int k = 1; k <= block[j].total; ++k) {
inv += GetSum(block[j].num[k] + 1);
Fix(block[j].num[k]);
}
ans[i][j] = inv;
}
}
for(int i = 1; i <= blocks; ++i)
sort(block[i].num + 1,block[i].num + block[i].total + 1);
for(int i = 1; i <= cnt; ++i) {
for(int j = 1; j < belong[i]; ++j)
g[i][j] = g[i][j - 1] + (block[j].total - (upper_bound(block[j].num + 1,block[j].num + block[j].total + 1,src[i]) - block[j].num) + 1);
for(int j = belong[i] + 1; j <= blocks; ++j)
g[i][j] = g[i][j - 1] + (lower_bound(block[j].num + 1,block[j].num + block[j].total + 1,src[i]) - block[j].num - 1);
}
int last_ans = 0;
cin >> asks;
for(int x,y,i = 1; i <= asks; ++i) {
scanf("%d%d",&x,&y);
x ^= last_ans,y ^= last_ans;
if(x > y) swap(x,y);
if(belong[x] == belong[y] || belong[x] == belong[y] - 1) {
int top = 0;
for(int j = x; j <= y; ++j)
temp[++top] = src[j];
printf("%d\n",last_ans = Calc(top));
continue;
}
int l = belong[x] + 1,r = belong[y] - 1;
int out = ans[l][r],top = 0;
for(int j = x; j <= _end[belong[x]]; ++j) {
out += g[j][r] - g[x][l - 1];
temp[++top] = src[j];
}
for(int j = _begin[belong[y]]; j <= y; ++j) {
out += g[j][r] - g[j][l - 1];
temp[++top] = src[j];
}
out += Calc(top);
printf("%d\n",last_ans = out);
}
return 0;
}