【bzoj3295】动态逆序对

Portal --> bzoj3295

Solution

  虽然说这个可能原本是一道愉快的树套树但是

​  没有强制在线并且是三维限制那就大力cdq分治啊!

  

​  看到“按照某个顺序依次删除”这样的字眼,比较容易联想到一个套路:反过来看,变成按照某个顺序依次插入

​  那么对于一个询问,删掉它之前(转化完了之后就是插入它之后)的所会影响到的逆序对数可以分为两种:一种是在它前面但是比它大的,一种是在它后面但是比它小的

​  对于每一个转化后的插入我们都计算出这样两个值的和,然后答案显然就是累加一下就好了

​  所以我们按照位置递增做一次cdq,然后再按照位置递减做一次cdq,就可以将上面两种情况分别算出来了

  总的来说就是:时间维用排序,位置维用cdq,数值维用树状数组,然后就很愉快滴做完了

​  注意因为一开始的时候我们将顺序反了过来所以最后要反着输出

  

  代码大概长这个样子:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=100010;
struct Op{
	int pos,val,t;
	friend bool operator < (Op x,Op y)
	{return x.t<y.t;}
}a[N],rec[N];
int lis[N],pos[N];
ll c[N],ans[N];
int n,m,tot,mx;

void insert(int x,int delta){
	for (;x;x-=x&-x) c[x]+=delta;
}
int query(int x){
	int ret=0;
	for (;x<=mx;x+=x&-x) ret+=c[x];
	return ret;
}
void solve(int l,int r){
	if (l==r) return;
	int mid=l+r>>1;
	solve(l,mid);
	solve(mid+1,r);
	int tmp,tp=l,tot=l-1;
	for (int i=mid+1;i<=r;++i){
		while (tp<=mid&&a[tp].pos<a[i].pos)
			rec[++tot]=a[tp],insert(a[tp++].val,1);
		rec[++tot]=a[i];
		ans[a[i].t]+=query(a[i].val+1);
	}
	for (int i=l;i<tp;++i) insert(a[i].val,-1);
	for (int i=tp;i<=mid;++i) rec[++tot]=a[i];
	for (int i=l;i<=r;++i) a[i]=rec[i];
}

int main(){/*{{{*/
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	int x;
	scanf("%d%d",&n,&m);
	mx=0;
	for (int i=1;i<=n;++i) 
		scanf("%d",&a[i].val),a[i].pos=i,pos[a[i].val]=i,mx=max(mx,a[i].val);
	for (int i=1;i<=m;++i){
		scanf("%d",&x);
		a[pos[x]].t=m-i+1;
	}
	sort(a+1,a+1+n);
	solve(1,n);
	for (int i=1;i<=n;++i) 
		a[i].pos*=-1,a[i].val=n-a[i].val+1;
	sort(a+1,a+1+n);
	solve(1,n);
	for (int i=1;i<=m;++i) ans[i]+=ans[i-1];
	for (int i=1;i<=m;++i)
		printf("%lld\n",ans[m-i+1]);
}/*}}}*/
posted @ 2018-07-16 16:46  yoyoball  阅读(258)  评论(0编辑  收藏  举报