题目大意:强制在线区间无修改逆序对。
思路:看到数据范围发现分块是很显然的。预处理了很多东西,比如说每个块里面的逆序对个数,还有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; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/41947475