1. 程式人生 > >[bzoj] 3295 動態逆序對 || CDQ分治

[bzoj] 3295 動態逆序對 || CDQ分治

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分治