您的位置:首页 > 其它

bzoj3295 [Cqoi2011]动态逆序对(cdq分治+树状数组)

2018-01-15 22:13 513 查看
我们把删除操作倒着考虑,变成逐渐加数,每个数按加入的顺序给时间标号ti。(没被删过的数随便按顺序给时间标号1…n-m),每个点我们记录三个信息(ti,xi,yi)分别表示时间标号,位置,数值,每一个点又都是一个询问,答案是加入这个点后增加的逆序对数。那么对于一个询问(t,x,y),他的答案就是满足

ti< t&&xi< x&&yi>y或者ti< t&&xi>x &&yi< y的点的个数。因此我们就是要求三维偏序。先按时间t排好序,然后每次分治里按x排序,y用树状数组来维护。因为有两种偏序要统计,因此我们要做两遍。最后的答案我们要做个前缀和,然后倒序输出对应的m个即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x7fffffff
#define N 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,a
,pos
,c
;
ll ans
;
bool del
;
struct event{
int x,y,t;
}e
,e1
,tmp
;
inline void add(int x,int val){for(;x<=n;x+=x&-x) c[x]+=val;}
inline int ask(int x){int res=0;for(;x;x-=x&-x) res+=c[x];return res;}
inline void cdq(int l,int r){
if(l==r) return;
int mid=l+r>>1;cdq(l,mid);cdq(mid+1,r);
int p1=l,p2=mid+1,owo=l;
while(owo<=r){//先统计i前面的数和i构成的逆序对
if(p2>r||p1<=mid&&e[p1].x<e[p2].x)
add(e[p1].y,1),tmp[owo++]=e[p1++];
else ans[e[p2].t]+=ask(n)-ask(e[p2].y),tmp[owo++]=e[p2++];
}for(int i=l;i<=mid;++i) add(e[i].y,-1);
memcpy(e+l,tmp+l,sizeof(e[0])*(r-l+1));
p1=l;p2=mid+1;owo=l;
while(owo<=r){//倒着插入,统计i后面的数和i构成的逆序对
if(p2>r||p1<=mid&&e1[p1].x>e1[p2].x)
add(e1[p1].y,1),tmp[owo++]=e1[p1++];
else ans[e1[p2].t]+=ask(e1[p2].y-1),tmp[owo++]=e1[p2++];
}for(int i=l;i<=mid;++i) add(e1[i].y,-1);
memcpy(e1+l,tmp+l,sizeof(e1[0])*(r-l+1));
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();int tot=n;
for(int i=1;i<=n;++i) a[i]=read(),pos[a[i]]=i;
for(int i=1;i<=m;++i){
int x=read();e[tot].t=tot;e[tot].x=pos[x];e[tot].y=x;
--tot;del[x]=1;
}for(int i=1;i<=n;++i){
if(del[a[i]]) continue;
e[tot].t=tot;e[tot].x=i;e[tot].y=a[i];--tot;
}memcpy(e1,e,sizeof(e1));cdq(1,n);
for(int i=2;i<=n;++i) ans[i]+=ans[i-1];
for(int i=n,cnt=1;cnt<=m;--i,++cnt) printf("%lld\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: