动态逆序对[CQOI2011]

此题正解 树套树
&&CDQ也要会啦

洛谷

首先按删除顺序,给每个点赋时间值,没删的赋inf
按时间从小到大排序,后删除的对先删除的莫得贡献,但是先删除的对后删除的有贡献

第二维 按pos值从小到大排序

维护两个东西
{posi<posj&&vali>valj}

{posi>posj&&vali<valj}

然后 莫得了

#include<bits/stdc++.h>
#define re return
#define lowbit(x) (x&(-x))
#define inc(i,l,r) for(int i=l;i<=r;++i)
#define dec(i,l,r) for(int i=l;i>=r;--i)
const int maxn=100005;
using namespace std;
template<typename T>inline void rd(T& x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

int n,m,c[maxn],pos[maxn],d[maxn];
long long ans;

struct node{
	int timme,val,pos,ans;
	bool operator<(node a)const
	{re timme<a.timme;}
}num[maxn],t[maxn];

inline void add(int x,int y){while(x<=n){c[x]+=y;x+=lowbit(x);}} 
inline int sum(int x)
{
	int res=0;
	while(x)
	{res+=c[x];x-=lowbit(x);}
	re res;
}

inline void CDQ(int l,int r)
{
	if(l==r) re;
	int mid=(l+r)>>1;
	CDQ(l,mid),CDQ(mid+1,r);
	int q=r,tot=l;
	dec(i,mid,l)
	{
		while(q>mid&&num[q].pos>num[i].pos)add(num[q].val,1),--q;
		num[i].ans+=sum(num[i].val-1);
	}
	inc(i,q+1,r)add(num[i].val,-1);
	
	q=mid+1;
	inc(i,l,mid)
	{
		while(q<=r&&num[q].pos<num[i].pos)
		{
			add(num[q].val,1);
			t[tot++]=num[q];
			++q;
		}
		num[i].ans+=sum(n)-sum(num[i].val);
		t[tot++]=num[i];
	}
	
	inc(i,mid+1,q-1)add(num[i].val,-1);
	inc(i,l,tot-1)num[i]=t[i];
	inc(i,tot,r)num[i]=num[q++];
}
int main()
{	
	freopen("in.txt","r",stdin);
	int x;
	rd(n);rd(m);
	inc(i,1,n)
	{
		rd(num[i].val);
		num[i].pos=i;
		pos[num[i].val]=i;
		num[i].timme=n;
	}
	
	inc(i,1,m)
	{
		rd(d[i]);
		num[pos[d[i]]].timme=i;
	}
	
	sort(num+1,num+n+1);
	CDQ(1,n);
	
	
	inc(i,1,n)ans+=num[i].ans;
	
	inc(i,1,m)
	{
		printf("%d
",ans);
		ans-=num[pos[d[i]]].ans;
	}
    re 0;
} 
原文地址:https://www.cnblogs.com/lsyyy/p/11336775.html