【题解】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;
}

浙公网安备 33010602011771号