Jzoj1020 逆序对统计 ≈ Bzoj3295 动态逆序对
Jzoj1020:
Dramatic是在太菜了。最近,他学习了有关逆序对的知识,并且掌握了计算一个序列逆序对个数的高效算法,因此,他兴冲冲的跑去向YY牛炫耀。YY牛对此不屑一顾,并打击Dramatic说:“这是在太小儿科了!”Dramatic很不甘心,于是在他的强烈要求下,YY牛给他出了一道跟逆序对有关的“难题”(显然,对于YY牛来说是简单题)。题目是这样的:YY牛首先给Dramatic一个长度为N的整数序列A。接下来,YY牛会对Dramatic说:把A的第i个数字改成j,同时告诉我现在A中逆序对的个数。重复了若干次之后,Dramatic已经算得头晕眼花,支撑不住了。然而,YY牛的命令一共有M个!为了解决这个问题,Dramatic只好你,你能够帮助Dramatic解决YY牛的“难题”吗?
两道题目差不多,这里一起讲
因为先做了上面那道,所以直接没考虑cdq写了BIT套主席树,结果被卡空间,乱搞了一下才过,不过特别好写是真的
#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define mid (l+r>>1)
using namespace std;
struct tree{ int l,r,s; } s[10000010];
int rt[100010],v[100010],n,m,cnt=0,ans=0;
inline void insert(int l,int r,int& x,int k){
if(!x) x=++cnt; ++s[x].s;
if(l==r) return;
if(k<=mid) insert(l,mid,s[x].l,k);
else insert(mid+1,r,s[x].r,k);
}
inline void remove(int l,int r,int& x,int k){
--s[x].s;
if(l==r) return;
if(k<=mid) remove(l,mid,s[x].l,k);
else remove(mid+1,r,s[x].r,k);
}
inline int gMin(int l,int r,int x,int k){
if(l==r) return 0;
if(k<=mid) return gMin(l,mid,s[x].l,k);
return s[s[x].l].s+gMin(mid+1,r,s[x].r,k);
}
inline int gMax(int l,int r,int x,int k){
if(l==r) return 0;
if(k>mid) return gMax(mid+1,r,s[x].r,k);
return s[s[x].r].s+gMax(l,mid,s[x].l,k);
}
int cal(int v,int p){
int ans=0;
for(int x=p;x;x&=x-1) ans+=gMax(1,50000,rt[x],v);
for(int x=n;x;x&=x-1) ans+=gMin(1,50000,rt[x],v);
for(int x=p;x;x&=x-1) ans-=gMin(1,50000,rt[x],v);
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",v+i);
for(int j=i;j<=n;j+=j&-j)
insert(1,50000,rt[j],v[i]);
}
for(int i=1;i<=n;++i)
ans+=cal(v[i],i);
scanf("%d",&m); ans>>=1;
for(int x,y;m--;){
scanf("%d%d",&x,&y);
ans-=cal(v[x],x);
for(int j=x;j<=n;j+=j&-j){
remove(1,50000,rt[j],v[x]);
insert(1,50000,rt[j],y);
}
ans+=cal(v[x]=y,x);
printf("%d\n",ans);
}
}
于是顺便切掉了bzoj3295,直接用上一题板子,简直比cdq短(man)太多
#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define mid (l+r>>1)
using namespace std;
struct tree{ int l,r,s; } s[10000010];
int rt[250010],v[250010],n,m,cnt=0,p[100010]; long long ans=0;
inline void insert(int l,int r,int& x,int k){
if(!x) x=++cnt; ++s[x].s;
if(l==r) return;
if(k<=mid) insert(l,mid,s[x].l,k);
else insert(mid+1,r,s[x].r,k);
}
inline void remove(int l,int r,int& x,int k){
--s[x].s;
if(l==r) return;
if(k<=mid) remove(l,mid,s[x].l,k);
else remove(mid+1,r,s[x].r,k);
}
inline int gMin(int l,int r,int x,int k){
if(l==r) return 0;
if(k<=mid) return gMin(l,mid,s[x].l,k);
return s[s[x].l].s+gMin(mid+1,r,s[x].r,k);
}
inline int gMax(int l,int r,int x,int k){
if(l==r) return 0;
if(k>mid) return gMax(mid+1,r,s[x].r,k);
return s[s[x].r].s+gMax(l,mid,s[x].l,k);
}
int cal(int v,int p){
int ans=0;
for(int x=p;x;x&=x-1) ans+=gMax(1,n,rt[x],v);
for(int x=n;x;x&=x-1) ans+=gMin(1,n,rt[x],v);
for(int x=p;x;x&=x-1) ans-=gMin(1,n,rt[x],v);
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",v+i); p[v[i]]=i;
for(int j=i;j<=n;j+=j&-j)
insert(1,n,rt[j],v[i]);
}
for(int i=1;i<=n;++i) ans+=cal(v[i],i);
ans>>=1;
for(int x,y;m--;){
printf("%lld\n",ans);
scanf("%d",&x); x=p[x];
ans-=cal(v[x],x);
for(int j=x;j<=n;j+=j&-j)
remove(1,n,rt[j],v[x]);
}
}