bzoj3289: Mato的文件管理
传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3289
思路:比较裸的莫队。
交换次数显然是逆序对个数...
然后考虑怎么从[l,r]的逆序对个数得到[l,r+1]的逆序对个数。
先离散化,用树状数组维护权值,我们只要考虑对于新加进来的这个数,原区间中有多少个数大于它,拿区间长度去减就可以得到这个数的贡献。
删除一个数类似。
复杂度O(n^1.5*logn)
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> const int maxn=50010; using namespace std; struct data{int id,rank;}file[maxn]; struct que{int l,r,id;}q[maxn]; int n,m,sz,a[maxn],bel[maxn],ans[maxn],cnt,res,T[maxn]; bool cmp(data a,data b){return a.rank<b.rank;} bool cmp2(que a,que b){return bel[a.l]==bel[b.l]?a.r<b.r:bel[a.l]<bel[b.l];} void modify(int x,int add){for (;x<=n;x+=x&(-x)) T[x]+=add;} int query(int x){int res=0;for (;x;x-=x&(-x)) res+=T[x];return res;} void work(){ for (int i=1,l=1,r=0;i<=m;i++){ for (;r<q[i].r;r++) res+=(r-l+1-query(a[r+1])),modify(a[r+1],1); for (;r>q[i].r;r--) res-=(r-l+1-query(a[r])),modify(a[r],-1); for (;l<q[i].l;l++) res-=query(a[l]-1),modify(a[l],-1); for (;l>q[i].l;l--) res+=query(a[l-1]-1),modify(a[l-1],1); ans[q[i].id]=res; } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); } int main(){ scanf("%d",&n);sz=sqrt(n); for (int i=1;i<=n;i++) bel[i]=(i-1)/sz+1; for (int i=1;i<=n;i++) scanf("%d",&file[i].rank),file[i].id=i; sort(file+1,file+1+n,cmp); for (int i=1;i<=n;i++){if (file[i].rank!=file[i-1].rank) ++cnt;a[file[i].id]=cnt;} scanf("%d",&m); for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; sort(q+1,q+1+m,cmp2),work(); return 0; }