[bzoj] 3295 動態逆序對 || CDQ分治
阿新 • • 發佈:2017-12-18
blog 順序 lld online 添加 namespace har -i pre
原題
給1到n的一個排列,按照某種順序依次刪除m個元素,求每刪除一個元素之前統計整個序列的逆序對數。
CDQ板題。因為刪除不好處理,所以將其反過來,變為每次添加。每個數都賦予一個添加時間,每次”刪除“操作後都是一次詢問操作。
三維分別為時間,位置,大小。
某個元素加入後產生的貢獻為時間更小、位置更小、數更大的個數 + 時間更小、位置更大、數更小的個數。
#include<cstdio>
#include<algorithm>
#define N 1000010
typedef long long ll;
using namespace std;
struct hhh
{
ll pos,w,tm;
bool operator < (const hhh &b) const
{
return tm<b.tm;
}
}p[N];
ll n,m,ans[N],f[N],x;
bool cmp(hhh a,hhh b)
{
return a.w>b.w;
}
ll read()
{
ll ans=0,fu=1;
char j=getchar();
for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
return ans*fu;
}
void add(int x,int y)
{
while (x<=n) f[x]+=y,x+=x&-x;
}
ll query(int x)
{
int ans=0;
while (x) ans+=f[x],x-=x&-x;
return ans;
}
void solve(int l,int r)
{
if (l==r) return ;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
sort(p+l,p+mid+1,cmp);
sort(p+mid+1,p+r+1,cmp);
int ll=l,rr=mid+1;
while (rr<=r)
{
while (ll<=mid && p[ll].w>p[rr].w)
add(p[ll].pos,1),ll++;
ans[p[rr].tm]+=query(p[rr].pos);
rr++;
}
while (--ll>=l) add(p[ll].pos,-1);//clear
ll=mid;
rr=r;
while (rr>mid)
{
while (ll>=l && p[ll].w<p[rr].w)
add(p[ll].pos,1),ll--;
ans[p[rr].tm]+=query(n)-query(p[rr].pos);
rr--;
}
while (++ll<=mid) add(p[ll].pos,-1);
}
int main()
{
n=read();
m=read();
for (int i=1;i<=n;i++)
{
x=read();
p[x].w=x;
p[x].pos=i;
}
for (int i=1;i<=m;i++)
{
x=read();
p[x].tm=n-i+1;//插入時間,倒敘按插入處理
}
for (int i=1,cnt=1;i<=n;i++)
if (!p[i].tm) p[i].tm=cnt++;
sort(p+1,p+n+1);
solve(1,n);
for (int i=2;i<=n;i++)
ans[i]+=ans[i-1];
for (int i=n;i>n-m;i--)
printf("%lld\n",ans[i]);
return 0;
}
[bzoj] 3295 動態逆序對 || CDQ分治