bzoj 3295 动态逆序对 (三维偏序,CDQ+树状数组)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3295
思路:
可以将这道题看成倒着插入,这样就可以转化成求逆序对数,用CDQ分治降维,正反用树状数组求两遍逆序对就好了。
这道题还可以用在线的树套树或者可持久化线段树来写。。
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int M = 2e5+10; struct node{ int t,x,y; int kind,id; node() {} node(int a,int b,int c,int d,int e = 0):t(a),x(b),y(c),kind(d),id(e){} bool operator < (const node &k) const { if(x == k.x) return y<k.y; return x < k.x; } }; int n,m,a[M],pos[M],x,c[M],tim,len; node q[M],t[M]; ll ans[M]; void add(int x,int val){ while(x <= n){ c[x] += val; x += (x&-x); } } int getsum(int x){ int sum = 0; while(x){ sum += c[x]; x -= (x&-x); } return sum; } void cdq(int l,int r){ if(l == r) return ; int mid = (l + r) >> 1; for(int i = l;i <= r;i ++){ if(q[i].t <= mid) add(q[i].y,q[i].kind); else ans[q[i].id] += q[i].kind*(getsum(n) - getsum(q[i].y)); } for(int i = l;i <= r;i ++) if(q[i].t <= mid) add(q[i].y,-q[i].kind); for(int i = r;i >= l;i --){ if(q[i].t <= mid) add(q[i].y,q[i].kind); else ans[q[i].id] += q[i].kind*getsum(q[i].y-1); } for(int i = l;i <= r;i ++) if(q[i].t <= mid) add(q[i].y,-q[i].kind); int L = l,R = mid+1; for(int i = l;i <= r;i ++){ if(q[i].t <= mid) t[L++] = q[i]; else t[R++] = q[i]; } for(int i = l;i <= r;i ++) q[i] = t[i]; cdq(l,mid); cdq(mid+1,r); } int main() { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i ++){ scanf("%d",&a[i]); pos[a[i]] = i; q[++len] = node(++tim,i,a[i],1,0); } for(int i = 1;i <= m;i ++){ scanf("%d",&x); q[++len] = node(++tim,pos[x],x,-1,i); } sort(q+1,q+1+len); cdq(1,len); for(int i = 1;i <= m;i ++){ ans[i] += ans[i-1]; printf("%lld\n",ans[i-1]); } return 0; }