题目大意:给出一段序列,求一个区间内的逆序对数量.
思路:又是没有修改的查询操作,又可以搞莫队了(莫队真好搞..
先把所有的询问排序,然后从头到位进行转移,记一个全局的答案,然后每次转移的时候记录逆序对的改变情况.然后从ans数组中输出..
CODE:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 50010 using namespace std; struct Ask{ int x,y,_id; int block; bool operator <(const Ask &a)const { if(block == a.block) return y < a.y; return block < a.block; } void Read(int p) { scanf("%d%d",&x,&y); _id = p; } }ask[MAX]; int cnt,asks; int src[MAX]; int fenwick[MAX]; pair<int,int *> xx[MAX]; int ans[MAX]; inline int GetSum(int x) { if(!x) return 0; int re = 0; for(; x; x -= x&-x) re += fenwick[x]; return re; } inline void Fix(int x,int c) { for(; x <= cnt; x += x&-x) fenwick[x] += c; } int main() { cin >> cnt; for(int i = 1; i <= cnt; ++i) scanf("%d",&xx[i].first),xx[i].second = &src[i]; sort(xx + 1,xx + cnt + 1); int t = 0; for(int i = 1; i <= cnt; ++i) { if(!t || xx[i].first != xx[i - 1].first) ++t; *xx[i].second = t; } cin >> asks; for(int i = 1; i <= asks; ++i) { ask[i].Read(i); } int block = static_cast<int>(sqrt(cnt)); for(int i = 1; i <= asks; ++i) ask[i].block = ask[i].x / block; sort(ask + 1,ask + asks + 1); int l = 1,r = 0; int now = 0; for(int i = 1; i <= asks; ++i) { while(r < ask[i].y) { int total = r - l + 1,larger = total - GetSum(src[++r]); now += larger; Fix(src[r],1); } while(l > ask[i].x) { now += GetSum(src[--l]); Fix(src[l],1); } while(r > ask[i].y) { int total = r - l + 1,larger = total - GetSum(src[r]); now -= larger; Fix(src[r--],-1); } while(l < ask[i].x) { now -= GetSum(src[l] - 1); Fix(src[l++],-1); } ans[ask[i]._id] = now; } for(int i = 1; i <= asks; ++i) printf("%d\n",ans[i]); return 0; }