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]);
    }
}

posted @ 2017-12-11 21:08  扩展的灰(Extended_Ash)  阅读(148)  评论(0编辑  收藏  举报