【传送门:BZOJ3289】
简要题意:
给出n个数,有m个询问,每个询问输入l,r,求出l到r中的所有数通过与相邻数交换变为上升序列的交换次数
题解:
一开始想用在线算法做
想不出来就用离线了
就想到用莫队
然后对于操作的继承,发现:
①在一列数的后面添加一个数,逆序对数会增加数列中比它大的数的个数。
②在一列数的后面删除一个数,逆序对数会减少数列中比它大的数的个数。
③在一列数的前面添加一个数,逆序对数会增加数列中比它小的数的个数。
④在一列数的前面删除一个数,逆序对数会减少数列中比它小的数的个数。
以上抠神犇博客(因为我太懒了,发现了这些之后懒得写。。)
设a[i]为当前l到r区间内>=i的数的个数,自然(r-l+1)-a[i]为当前l到r区间内<i的数的个数
发现要区间修改值,原本想用线段树,后来发现树状数组差分可以做,就写了树状数组
我的代码略丑,因为如果l<r的情况不知道怎么的就会错,所以加了几句判断
一把辛酸泪
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct LS { int d,id; }s[51000]; struct qn { int l,r,id; LL d; }q[51000]; int bk[51000]; bool cmp(qn n1,qn n2) { return bk[n1.l]==bk[n2.l]?n1.r<n2.r:bk[n1.l]<bk[n2.l]; } bool cmpd(qn n1,qn n2) { return n1.id<n2.id; } bool lsd(LS n1,LS n2) { return n1.d<n2.d; } bool lsid(LS n1,LS n2) { return n1.id<n2.id; } LL a[51000]; int lowbit(int x){return x&-x;} int n; LL getsum(int x) { LL ans=0; while(x!=0) { ans+=a[x]; x-=lowbit(x); } return ans; } void change(int x,LL c) { while(x<=n) { a[x]+=c; x+=lowbit(x); } } LL t[51000]; int main() { scanf("%d",&n); int block=int(sqrt(n)); for(int i=1;i<=n;i++) { scanf("%d",&s[i].d); s[i].id=i; bk[i]=(i-1)/block+1; } sort(s+1,s+n+1,lsd); for(int i=1;i<=n;i++) s[i].d=i; sort(s+1,s+n+1,lsid); int m; 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+m+1,cmp); int l=1,r=0; LL ans=0; memset(a,0,sizeof(a)); for(int i=1;i<=m;i++) { while(l<q[i].l) { if(l>r){l++;continue;} ans-=(r-l+1)-getsum(s[l].d); change(1,-1); if(s[l].d!=n) change(s[l].d+1,1); l++; } while(l>q[i].l) { if(l>r+1){l--;continue;} ans+=(r-l+1)-getsum(s[l-1].d); l--; change(1,1); if(s[l].d!=n) change(s[l].d+1,-1); } while(r<q[i].r) { if(l>r+1){r++;continue;} ans+=getsum(s[r+1].d); r++; change(1,1); if(s[r].d!=n) change(s[r].d+1,-1); } while(r>q[i].r) { if(l>r){r--;continue;} ans-=getsum(s[r].d)-1; change(1,-1); if(s[r].d!=n) change(s[r].d+1,1); r--; } q[i].d=ans; } sort(q+1,q+m+1,cmpd); for(int i=1;i<=m;i++) printf("%lld\n",q[i].d); return 0; }