【BZOJ3295】动态逆序对
题意:
给 \(1\) 到 \(n\) 的一个排列,按照某种顺序依次删除 \(m\) 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
题解:
将操作离线反转,将删除操作看做插入操作。
设一个点 \(i\) 的位置为 \(p_i\), 插入的时间为 \(t_i\), 权值为 \(w_i\) , 那么 \(i\) 的贡献即为 \(\sum_j [t_j<t_i,p_j<p_i,w_j>w_i]+\sum_j [t_j>t_i,p_j>p_i,w_j<w_i]\) .
我们发现这就是一个裸的三维偏序问题,直接用 cdq 做就可以了!
#include<cstdio>
#include<algorithm>
using namespace std;
inline int gi()
{
char c; int x=0;
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
return x;
}
const int N=100005;
struct node {
int x,y,id;
} q[N],tmp[N];
bool cmp1(node s, node t) {
return s.id<t.id;
}
bool cmp2(node s, node t) {
if(s.x!=t.x) return s.x<t.x;
if(s.y!=t.y) return s.y<t.y;
return s.id<t.id;
}
int n,m,a[N],pos[N];
long long ans[N],t[N];
bool vis[N];
#define lowbit(x) (x&-x)
void upd(int i, int w) {
for(;i<=n;i+=lowbit(i)) t[i]+=w;
}
int qry(int i) {
int r=0;
for(;i;i-=lowbit(i)) r+=t[i];
return r;
}
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+mid+1,cmp2);
sort(q+mid+1,q+r+1,cmp2);
int j=l;
for(int i=mid+1;i<=r;++i)
{
for(;j<=mid&&q[j].x<q[i].x;++j) upd(q[j].y,1);
ans[q[i].id]+=qry(n)-qry(q[i].y);
}
for(--j;j>=l;--j) upd(q[j].y,-1);
j=mid;
for(int i=r;i>mid;--i)
{
for(;j>=l&&q[j].x>q[i].x;--j) upd(q[j].y,1);
ans[q[i].id]+=qry(q[i].y);
}
for(++j;j<=mid;++j) upd(q[j].y,-1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1859.in","r",stdin);
#endif
n=gi(),m=gi();
for(int i=1;i<=n;++i) a[i]=gi(),pos[a[i]]=i;
int cnt=n;
for(int i=1;i<=m;++i)
{
int x=gi();
q[i]=(node){pos[x],x,cnt--};
vis[x]=true;
} int mm=m;
for(int i=1;i<=n;++i)
if(!vis[a[i]]) q[++mm]=(node){i,a[i],cnt--};
sort(q+1,q+1+n,cmp1);
cdq(1,n);
for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
for(int i=n;i>n-m;--i) printf("%lld\n",ans[i]);
}