3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1373 Solved: 465
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
1
5
3
4
2
5
1
4
2
Sample Output
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
CDQ分治+树状数组
orz PoPoQQQ(解题方法和代码都是copy他的。。)
首先我们可以用树状数组求出初始解;
并求出cnt[i],表示i所在的逆序对数:1.在他之前插入了比他大的 2.在他之后插入了比他小的
(注意:为了避免每次都清空树状数组,我们可以用一个时间戳)
但是删除一个数x之后,不能单纯的只减去cnt[x],因为如果逆序对是(x,y),y在之前被删除了,那么之前就已经减过这个逆序对了,这次再减就导致多减了一次。
因此每次在减掉cnt[x]的时候还要加上f[i]:
表示当前要删的数字与之前已经删过的数字构成了几对逆序对。
(这是一个三维的问题了:时间,位置,权值)
我们用CDQ分治来求f[i]。
q[i].x,q[i].y,q[i].pos分别表示删除的数字,删除数字所在的位置,被删除的时间。
按照q[i].y升序排序,递归处理完(l,mid)之后,计算(l,mid)对(mid+1,r)的影响(此时只剩下权值一维):
还是分两种情况:1.在他之前比他大的 2.在他之后比他小的
然后就可以递归解决(mid+1,r)了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define LL long long
#define M 100005
using namespace std;
LL ans=0,f[M],cnt[M];
int t[M],n,m,ti[M],now=0,a[M],b[M];
struct query
{
int x,y,pos;
}q[M],nq[M];
int lowbit(int x)
{
return x&(-x);
}
int Getsum(int x,int k)
{
int ans=0;
for (int i=x;i&&i<=n;i+=lowbit(i)*k)
if (ti[i]==now)
ans+=t[i];
return ans;
}
void Push_up(int x,int k)
{
for (int i=x;i&&i<=n;i+=lowbit(i)*k)
{
if (ti[i]!=now)
ti[i]=now,t[i]=0;
t[i]+=1;
}
}
bool cmp(query a,query b)
{
return a.y<b.y;
}
void CDQ(int l,int r)
{
if (l==r)
{
printf("%lld\n",ans);
ans=ans-cnt[q[l].y]+f[l];
return;
}
int mid=(l+r)>>1;
int l1=l,l2=mid+1;
for (int i=l;i<=r;i++)
if (q[i].pos<=mid)
nq[l1++]=q[i];
else
nq[l2++]=q[i];
memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1));
CDQ(l,mid);
now++;
int j=l;
for (int i=mid+1;i<=r;i++)
{
for (;j<=mid&&q[j].y<q[i].y;j++)
Push_up(q[j].x,-1);
f[q[i].pos]+=Getsum(q[i].x,1);
}
now++;j=mid;
for (int i=r;i>mid;i--)
{
for (;j>=l&&q[j].y>q[i].y;j--)
Push_up(q[j].x,1);
f[q[i].pos]+=Getsum(q[i].x,-1);
}
CDQ(mid+1,r);
l1=l,l2=mid+1;
for (int i=l;i<=r;i++)
if ((q[l1].y<q[l2].y||l2>r)&&l1<=mid)
nq[i]=q[l1++];
else nq[i]=q[l2++];
memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1));
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),b[a[i]]=i;
for (int i=1;i<=n;i++)
{
cnt[i]=Getsum(a[i],1);
Push_up(a[i],-1);
ans+=cnt[i];
}
now++;
for (int i=n;i;i--)
{
cnt[i]+=Getsum(a[i],-1);
Push_up(a[i],1);
}
for (int i=1;i<=m;i++)
{
scanf("%d",&q[i].x);
q[i].y=b[q[i].x];
q[i].pos=i;
}
sort(q+1,q+1+m,cmp);
CDQ(1,m);
return 0;
}