题目大意:给出一个数列,支持交换两个数字的操作,问每次操作之后的逆序对数量。
思路:数字比较大,先离散化。然后先求一次总逆序对,每次交换两个数字的时候用树套树维护一下逆序对的总数就可以了。。
好像树套树的常数略大,正解应该是分块。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 20010 using namespace std; #define QR QuickRead #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define SIZE(a) ((a) == NULL ? 0:(a)->size) namespace QuickRead{ inline int GetChar() { static const int L = 1 << 15; static char buf[L],*S = buf,*T = buf; if(S == T) { T = (S = buf) + fread(buf,1,L,stdin); if(S == T) return EOF; } return *S++; } template<typename T> inline void Get(T &x) { static char c; while(!isdigit(c = GetChar())); x = c - '0'; while(isdigit(c = GetChar())) x = (x << 1) + (x << 3) + c - '0'; } } int cnt,asks,src[MAX]; pair<int,int *> xx[MAX]; int fenwick[MAX]; inline void Fix(int x) { for(; x; x -= x&-x) ++fenwick[x]; } inline int GetSum(int x) { int re = 0; for(; x < MAX; x += x&-x) re += fenwick[x]; return re; } struct Treap{ int val,random,cnt,size; Treap *son[2]; Treap(int _) { val = _; random = rand(); cnt = size = 1; son[0] = son[1] = NULL; } int Compare(int x) { if(x == val) return -1; return x > val; } void Maintain() { size = cnt; if(son[0] != NULL) size += son[0]->size; if(son[1] != NULL) size += son[1]->size; } }*tree[MAX << 2]; inline void Rotate(Treap *&a,bool dir) { Treap *k = a->son[!dir]; a->son[!dir] = k->son[dir]; k->son[dir] = a; a->Maintain(),k->Maintain(); a = k; } void Insert(Treap *&a,int x) { if(a == NULL) { a = new Treap(x); return ; } int dir = a->Compare(x); if(dir == -1) ++a->cnt; else { Insert(a->son[dir],x); if(a->son[dir]->random > a->random) Rotate(a,!dir); } a->Maintain(); } void Delete(Treap *&a,int x) { int dir = a->Compare(x); if(dir != -1) Delete(a->son[dir],x); else { if(a->cnt > 1) --a->cnt; else { if(a->son[0] == NULL) a = a->son[1]; else if(a->son[1] == NULL) a = a->son[0]; else { int _dir = a->son[0]->random > a->son[1]->random; Rotate(a,_dir); Delete(a->son[_dir],x); } } } if(a != NULL) a->Maintain(); } int Lower(Treap *a,int x) { if(a == NULL) return 0; if(a->val >= x) return Lower(a->son[0],x); return SIZE(a->son[0]) + a->cnt + Lower(a->son[1],x); } int Upper(Treap *a,int x) { if(a == NULL) return 0; if(a->val <= x) return Upper(a->son[1],x); return SIZE(a->son[1]) + a->cnt + Upper(a->son[0],x); } inline void BuildTree(int l,int r,int pos) { for(int i = l; i <= r; ++i) Insert(tree[pos],src[i]); if(l == r) return ; int mid = (l + r) >> 1; BuildTree(l,mid,LEFT); BuildTree(mid + 1,r,RIGHT); } int Lower(int l,int r,int x,int y,int val,int pos) { if(l == x && y == r) return Lower(tree[pos],val); int mid = (l + r) >> 1; if(y <= mid) return Lower(l,mid,x,y,val,LEFT); if(x > mid) return Lower(mid + 1,r,x,y,val,RIGHT); int left = Lower(l,mid,x,mid,val,LEFT); int right = Lower(mid + 1,r,mid + 1,y,val,RIGHT); return left + right; } int Upper(int l,int r,int x,int y,int val,int pos) { if(l == x && y == r) return Upper(tree[pos],val); int mid = (l + r) >> 1; if(y <= mid) return Upper(l,mid,x,y,val,LEFT); if(x > mid) return Upper(mid + 1,r,x,y,val,RIGHT); int left = Upper(l,mid,x,mid,val,LEFT); int right = Upper(mid + 1,r,mid + 1,y,val,RIGHT); return left + right; } void Delete(int l,int r,int x,int val,int pos) { Delete(tree[pos],val); if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Delete(l,mid,x,val,LEFT); else Delete(mid + 1,r,x,val,RIGHT); } void Insert(int l,int r,int x,int val,int pos) { Insert(tree[pos],val); if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Insert(l,mid,x,val,LEFT); else Insert(mid + 1,r,x,val,RIGHT); } int main() { cin >> cnt; for(int i = 1; i <= cnt; ++i) { QR::Get(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(i == 1 || xx[i].first != xx[i - 1].first) ++t; *xx[i].second = t; } int inv = 0; for(int i = 1; i <= cnt; ++i) { inv += GetSum(src[i] + 1); Fix(src[i]); } cout << inv << endl; BuildTree(1,cnt,1); int x,y; for(QR::Get(asks); asks--;) { QR::Get(x),QR::Get(y); if(x > y) swap(x,y); if(x + 1 != y) { inv -= Lower(1,cnt,x + 1,y - 1,src[x],1); inv += Upper(1,cnt,x + 1,y - 1,src[x],1); inv -= Upper(1,cnt,x + 1,y - 1,src[y],1); inv += Lower(1,cnt,x + 1,y - 1,src[y],1); } Delete(1,cnt,x,src[x],1); Insert(1,cnt,x,src[y],1); Delete(1,cnt,y,src[y],1); Insert(1,cnt,y,src[x],1); if(src[x] < src[y]) ++inv; if(src[x] > src[y]) --inv; swap(src[x],src[y]); printf("%d\n",inv); } return 0; }