BZOJ3295 [CQOI2011]动态逆序对
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
正解:cdq分治或带修改主席树
解题报告:为了好好练练主席树,强行把这道cdq水题用带修改主席树做一遍
#include <iostream> #include <iomanip> #include <cstdlib> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #define RG register #define ll long long const int N = 10000000; const int M = 200005; using namespace std; int gi(){ RG char ch=getchar();RG int x=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } struct dota{ int l,r; int s; }tr[N]; int rt[M],f[M],L[M],g[M],ra[M]; ll v[M],ans; int n,m,cnt; bool vis[M]; void build(int &x,int s,int l,int r){ if (x==0) x=++cnt; ++tr[x].s; if (l==r) return; int mid=(l+r)>>1; if (s<=mid) build(tr[x].l,s,l,mid); else build(tr[x].r,s,mid+1,r); return; } void work(int x,int s){ while(x<n){ build(rt[x],s,1,n); x+=x&(-x); } return; } int check(int x,int l,int r,int ql,int qr){ if (ql<=l && r<=qr) return tr[x].s; int mid=(l+r)>>1,ans=0; if (ql<=mid) ans+=check(tr[x].l,l,mid,ql,qr); if (qr>mid) ans+=check(tr[x].r,mid+1,r,ql,qr); return ans; } ll query(int x,int l,int r){ int k=0;ll s=0; while(x){ L[++k]=rt[x]; x-=x&(-x); } for (RG int i=1; i<=k; ++i) s+=check(L[i],1,n,l,r); return s; } int main(){ n=gi()+1,m=gi(); for (RG int i=1; i<n; ++i) f[i]=gi(),ra[f[i]]=i; for (RG int i=1; i<=m; ++i) g[i]=gi(),vis[g[i]]=1; for (RG int i=1; i<n; ++i) if (vis[f[i]]==0){ ans+=query(i,f[i]+1,n); ans+=query(n-1,1,f[i]); ans-=query(i,1,f[i]); work(i,f[i]); } for (RG int i=m; i>=1; --i){ int w=ra[g[i]]; work(w,g[i]); ans+=query(w,g[i]+1,n); ans+=query(n-1,1,g[i]); ans-=query(w,1,g[i]); v[i]=ans; } for (RG int i=1; i<=m; ++i) printf("%lld\n",v[i]); return 0; }