F - 动态逆序对
题目大意:给出一个序列有m个询问,每一个询问要求输出当前的逆序对数量后在原序列中删除该数字。
解题思路:如果将删除倒着做就变成了插入。没插入一个数字我们就统计当前数字对逆序对产生的贡献就是
这里有三维 插入的时间t 数字的值v 和 插入的位置pos
所以就转化为了三维偏序问题。
第一维是时间,第二维就是值 第三维是pos
对于每个查询我们就统计插入时间小于它的 位置小于它的值大于它的和位置大于他值小于它的
然后将查询做一个前缀和。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define lowb(x) (x&(-x))
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define pri(x) printf("%d\n",x);
#define N 100005
#define inf 0x3f3f3f3f
const LL mod=1e9+7;
struct node
{
int val,pos,qid;
}q[N*2];
int a[N],b[N],vis[N],vis1[N];
LL ou[N];
bool cmpy(node a,node b)
{
return a.val>b.val;
}
struct BIT
{
int c[N];
int maxn;
void init(int n)
{
maxn=n;
}
void add(int x,int val,int t)
{
if(t){
for(int i=x;i<=maxn;i+=lowb(i))c[i]+=val;
}
else{
for(int i=x;i;i-=lowb(i))c[i]+=val;
}
}
int ask(int x,int t)
{
int ans=0;
if(t){
for(int i=x;i;i-=lowb(i))ans+=c[i];
}
else{
for(int i=x;i<=maxn;i+=lowb(i))ans+=c[i];
}
return ans;
}
}bit;
void cdq(int l,int r)
{
if(l==r) return ;
int m=(l+r)>>1;
cdq(l,m);cdq(m+1,r);
sort(q+l,q+m+1,cmpy);
sort(q+m+1,q+r+1,cmpy);
int L=l,R=m+1;
for(;R<=r;R++)
{
while(q[L].val>q[R].val&&L<=m)
{
bit.add(q[L].pos,1,1);
L++;
}
ou[q[R].qid]+=bit.ask(q[R].pos,1);
}
for(int i=l;i<L;i++)bit.add(q[i].pos,-1,1);
R=r,L=m;
for(;R>m;R--)
{
while(q[L].val<q[R].val&&L>=l)
{
bit.add(q[L].pos,1,0);
L--;
}
ou[q[R].qid]+=bit.ask(q[R].pos,0);
}
for(int i=m;i>L;i--)bit.add(q[i].pos,-1,0);
}
int main()
{
int n,m;
cin>>n>>m;
bit.init(n);
rep(i,1,n)sca(a[i]),vis1[a[i]]=i;
rep(i,1,m)sca(b[i]),vis[b[i]]=1;
int tot=1;
int qid=1;
rep(i,1,n)
{
if(!vis[a[i]])q[tot++]=node{a[i],vis1[a[i]],qid++};
}
per(i,m,1)
{
q[tot++]=node{b[i],vis1[b[i]],qid++};
}
cdq(1,tot-1);
rep(i,2,qid-1)ou[i]+=ou[i-1];
per(i,qid-1,qid-m)printf("%lld\n",ou[i]);
}
虽然cdq分治还是很快的。但是cdq分治里边套sort感觉不太好,其实我们在cdq的过程中对第二维进行归并就可以了。
这样比原来大概快了一半。。。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define lowb(x) (x&(-x))
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define pri(x) printf("%d\n",x);
#define N 100005
#define inf 0x3f3f3f3f
const LL mod=1e9+7;
struct node
{
int val,pos,qid;
}q[N*2],q1[N];
int a[N],b[N],vis[N],vis1[N];
LL ou[N];
bool cmpy(node a,node b)
{
return a.val>b.val;
}
struct BIT
{
int c[N];
int maxn;
void init(int n)
{
maxn=n;
}
void add(int x,int val,int t)
{
if(t){
for(int i=x;i<=maxn;i+=lowb(i))c[i]+=val;
}
else{
for(int i=x;i;i-=lowb(i))c[i]+=val;
}
}
int ask(int x,int t)
{
int ans=0;
if(t){
for(int i=x;i;i-=lowb(i))ans+=c[i];
}
else{
for(int i=x;i<=maxn;i+=lowb(i))ans+=c[i];
}
return ans;
}
}bit;
void cdq(int l,int r)
{
if(l==r) return ;
int m=(l+r)>>1;
cdq(l,m);cdq(m+1,r);
int now=l;
int L=l,R=m+1;
for(;R<=r;R++)
{
while(q[L].val>q[R].val&&L<=m)
{
bit.add(q[L].pos,1,1);
q1[now++]=q[L];
L++;
}
ou[q[R].qid]+=bit.ask(q[R].pos,1);
q1[now++]=q[R];
}
for(int i=L;i<=m;i++)q1[now++]=q[i];
for(int i=l;i<L;i++)bit.add(q[i].pos,-1,1);
R=r,L=m;
for(;R>m;R--)
{
while(q[L].val<q[R].val&&L>=l)
{
bit.add(q[L].pos,1,0);
L--;
}
ou[q[R].qid]+=bit.ask(q[R].pos,0);
}
for(int i=m;i>L;i--)bit.add(q[i].pos,-1,0);
for(int i=l;i<=r;i++)q[i]=q1[i];
}
int main()
{
int n,m;
cin>>n>>m;
bit.init(n);
rep(i,1,n)sca(a[i]),vis1[a[i]]=i;
rep(i,1,m)sca(b[i]),vis[b[i]]=1;
int tot=1;
int qid=1;
rep(i,1,n)
{
if(!vis[a[i]])q[tot++]=node{a[i],vis1[a[i]],qid++};
}
per(i,m,1)
{
q[tot++]=node{b[i],vis1[b[i]],qid++};
}
cdq(1,tot-1);
rep(i,2,qid-1)ou[i]+=ou[i-1];
per(i,qid-1,qid-m)printf("%lld\n",ou[i]);
}