【题解】P3157 [CQOI2011] 动态逆序对

P3157】题解

一:【题面】

二:【解法】

每个点有属性{T,a,b}表{删除时间,位置,数值}
对于每个i,如果有j满足以下任意条件

  • T[j]>T[i],a[j]>a[i],b[j]<a[i]
  • T[j]>T[i],a[j]<a[i],b[j]>a[i]
    那么T[i]>T[j]的答案+1
    CDQ分治细节处理:
    第一次CDQ:T取负号,a取负号
    第二次CDQ:基于1的基础上,a取负号,b取负号
    对于每个i得到了T[j]>T[i]的逆序对个数
    按时间排序,累加后缀即为答案

三:【代码】

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
struct node{
	int t,a,b;
	int ans;
	node(){
		t=a=b=ans=0;
	}
}q[N];
bool cmpt(node x,node y){
	if(x.t!=y.t) return x.t<y.t;
	if(x.a!=y.a) return x.a<y.a;
	return x.b<y.b;
}
bool cmpa(node x,node y){
	if(x.a!=y.a) return x.a<y.a;
	return x.b<y.b;
}
int tree[N];
void update(int x,int d){
	while(x<N){
		tree[x]+=d;
		x+=x&-x;
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=tree[x];
		x-=x&-x;
	}
	return res;
}
void CDQ(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1;
	CDQ(l,mid);CDQ(mid+1,r);
	sort(q+l,q+1+mid,cmpa);sort(q+1+mid,q+r+1,cmpa);
	int i=l,j=mid+1;
	while(j<=r){
		while(i<=mid&&q[i].a<=q[j].a){
			update(q[i].b,1);
			i++;
		}
		//cout<<"-->"<<query(q[j].b)<<"\n";
		q[j].ans+=query(q[j].b);
		j++;
	}
	for(int k=l;k<i;k++) update(q[k].b,-1);
}
int ans[N];
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;i++){
		int k;cin>>k;
		q[k].a=i;
		q[k].b=k;
	}
	for(int i=1;i<=m;i++){
		int k;cin>>k;
		q[k].t=i;
	}
	int idx=m;
	for(int i=1;i<=n;i++){
		if(q[i].t==0) q[i].t=++idx;
	}
	
	
	for(int i=1;i<=n;i++){
		q[i].t=N-q[i].t;
		q[i].a=N-q[i].a;
	}
	sort(q+1,q+1+n,cmpt);
	CDQ(1,n);
	
	for(int i=1;i<=n;i++){
		q[i].b=N-q[i].b;
		q[i].a=N-q[i].a;
	}
	sort(q+1,q+1+n,cmpt);
	CDQ(1,n);
	
	for(int i=1;i<=n;i++){
		q[i].t=N-q[i].t;
		q[i].b=N-q[i].b;
	}
	for(int i=1;i<=n;i++) ans[q[i].t]+=q[i].ans;
	for(int i=idx;i>=1;i--) ans[i]+=ans[i+1];
	for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
	return 0;
}
posted @ 2025-12-26 17:47  Ming3398  阅读(9)  评论(0)    收藏  举报