CQOI2011 動態逆序對
阿新 • • 發佈:2018-12-09
href class 三維 bit str getc www. 逆序對 struct
傳送門
這道題其實我一開始直接的反應是分塊……不過聽說這是CDQ分治練習題。
看到這種刪除的題……一般就會想到先全刪光之後整回去。對於每次添加,我們要統計的就是添加在它之前的,位置在它之前的,比他大的,和添加在它之前的,位置在它之後的,比他小的。
形象地說,對於每一個操作i,給定三個值\(tim\),\(pos\),\(val\),我們相當於求的是對於一個\(i\),有多少個\(j\)使得\(tim_i < tim_j,pos_i < pos_j,val_i > val_j\)或者\(tim_i < tim_j,pos_i > pos_j,val_i < val_j\)
這其實就是一個三維偏序的變形。我的做法有點奇怪,我是對先對\(tim\)排序的,之後需要在分治的時候統計兩次。第一次統計的時候需要用已經計算過的點的個數減去統計的個數,這樣才是\(val\)值更大的元素的元素個數。
我把所有的沒有被刪去的點的\(tim\)都賦值為0,這樣的話會產生的問題是他會把一開始存在的逆序對多計算一倍,所以一開始除一下,之後計算前綴和就好了。
看一下代碼。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #include<vector> #include<map> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(‘\n‘) #define fr friend inline #define y1 poj #define mp make_pair #define pr pair<int,int> #define fi first #define sc second #define pb push_back #define lowbit(x) x & (-x) using namespace std; typedef long long ll; const int M = 100005; const int INF = 1000000009; const double eps = 1e-7; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) op = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { ans *= 10; ans += ch - ‘0‘; ch = getchar(); } return ans * op; } struct node { int val,pos,tim; bool operator < (const node &g)const { return tim < g.tim; } }a[M]; struct treearray { ll c[M]; void add(int x,int v){while(x <= M-2) c[x] += v,x += lowbit(x);} ll ask(int x){ll cur = 0;while(x) cur += c[x],x -= lowbit(x);return cur;} }T; int n,m,x,p[M]; ll ans[M]; void CDQ(int l,int r) { //printf("#%d %d\n",l,r); if(l == r) return; int mid = (l+r) >> 1,j = l; CDQ(l,mid),CDQ(mid+1,r); sort(a+l,a+mid+1),sort(a+mid+1,a+r+1); //rep(i,l,r) printf("#%d %d %d\n",a[i].pos,a[i].tim,a[i].val); rep(i,mid+1,r) { while(j <= mid && a[j].tim <= a[i].tim) T.add(a[j].val,1),j++; ans[a[i].tim] += j - l - T.ask(a[i].val); } rep(i,l,j-1) T.add(a[i].val,-1); j = mid+1; rep(i,l,mid) { while(j <= r && a[j].tim <= a[i].tim) T.add(a[j].val,1),j++; ans[a[i].tim] += T.ask(a[i].val-1); } rep(i,mid+1,j-1) T.add(a[i].val,-1); } int main() { n = read(),m = read(); rep(i,1,n) a[i].val = read(),a[i].pos = i,a[i].tim = 0,p[a[i].val] = i; rep(i,1,m) x = read(),a[p[x]].tim = m - i + 1; //rep(i,1,n) printf("#%d %d %d\n",a[i].pos,a[i].tim,a[i].val); CDQ(1,n); //rep(i,1,m) printf("%d ",ans[i]);enter; ans[1] += ans[0] >> 1; rep(i,2,m) ans[i] += ans[i-1]; per(i,m,1) printf("%lld\n",ans[i]); return 0; }
CQOI2011 動態逆序對