CQOI2011動態逆序對--cdq分治

題意:給出一個1~n的排列,按順序刪掉m個元素,求出每次刪除操作之前序列的逆序對個數.

做法:這題顯然可以用樹套樹之類的工業結構維護,但是我怎麼可能會呢.

考慮離線cdq分治,可以把問題反過來,轉化爲每次添加一個元素,求添加後序列的逆序對個數.

把每個元素看成平面上的點,x,y座標分別是元素大小和插入位置,產生貢獻的一對點則滿足(x<x')!=(y<y').

設f[i]是添加第i個元素後,包含i的逆序對個數,那麼只有之前添加的點對它產生影響,x維排序,y維用樹狀數組維護,然後x,y交換再做一遍就好了.

PS:之前排序用的sort,就T了,簡直太迷了.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define REP(I,ST,ED) for(int I=ST,I##end=ED;I<=I##end;++I)
#define DREP(I,ST,ED) for(int I=ST,I##end=ED;I>=I##end;--I)
typedef long long ll;
namespace ioput{
	int read(){
		int x=0;
		char c=getchar();
		while((c<'0')||(c>'9'))c=getchar();
		while((c>='0')&&(c<='9'))x=x*10+c-'0',c=getchar();
		return x;
	}
	char t[20];
	int tlen;
	void write(ll x){
		t[tlen=0]='\n';
		if(x==0)t[++tlen]=0;
		while(x)
			t[++tlen]=x%10+'0',x/=10;
		DREP(i,tlen,0)putchar(t[i]);
	}
}
using namespace ioput;
const int maxn=100005;
struct node{int x,y,id;}a[maxn],b[maxn],ta[maxn];
int n,m,tot,pos[maxn];
bool vis[maxn];
ll ans[maxn];
namespace Binary_Indexed_Tree{
	ll c[maxn];
	void add(int x,int val){
		while(x<=n)
			c[x]+=val,x+=x&-x;
	}
	int query(int x){
		int res=0;
		while(x)
			res+=c[x],x-=x&-x;
		return res;
	}
}
using namespace Binary_Indexed_Tree;
void solve(int l,int r){
	if(l>=r)return;
	int mid=(l+r)>>1,cur=l,curl=l,curr=mid+1;
	solve(l,mid),solve(mid+1,r);
	while((curl<=mid)&&(curr<=r)){
		if(a[curl].x<a[curr].x)add(a[curl].y,1),b[cur++]=a[curl++];
		else ans[a[curr].id]+=query(n)-query(a[curr].y),b[cur++]=a[curr++];
	}REP(i,curl,mid)b[cur++]=a[i];
	REP(i,curr,r)ans[a[i].id]+=query(n)-query(a[i].y),b[cur++]=a[i];
	REP(i,l,curl-1)add(a[i].y,-1);
	REP(i,l,r)a[i]=b[i];
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	int u,tmp=0;
	n=read(),m=read();
	REP(i,1,n)pos[read()]=i;
	DREP(i,n,n-m+1){
		vis[u=read()]=1;
		a[i]=(node){u,pos[u],i};
	}
	REP(i,1,n)
		if(!vis[i])
			a[++tmp]=(node){i,pos[i],tmp};
	REP(i,1,n)ta[i]=a[i];
	solve(1,n);
	REP(i,1,n)a[i]=ta[i],swap(a[i].x,a[i].y);
	solve(1,n);
	REP(i,1,n)ans[i]+=ans[i-1];
	DREP(i,n,n-m+1)write(ans[i]);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章