1. 程式人生 > >BZOJ 3295 [Cqoi2011]動態逆序對 樹狀陣列套線段樹

BZOJ 3295 [Cqoi2011]動態逆序對 樹狀陣列套線段樹

題意:連結

方法:樹狀陣列套線段樹

解析:

這題基本上寫的都是什麼CDQ點分治,主席樹之類的,然而這我都並不會,所以寫了一發平衡樹套線段樹想卡時卡過去,然而我並沒有得逞,T的不要不要的,這裡用平衡樹套線段樹的方法參見我的題解:排隊。這道題比那道更要簡單。

然後我就打算棄坑了~不過看140142做這道題做的熱火朝天的,還是打算回來做一下,yy下樹狀陣列套線段樹,然後去看hz的題解,只看懂他寫理論部分了,程式碼部分不知所云,所以還是還是得yy。引用理論部分。

刪除某個數,只要統計它之前還存在的比它大的數的個數,和之後還存在的比它小的數的個數

然後差不多就按照這個意思寫。

由於線段樹有一種神奇的性質,也就是它的每一層不會有交叉,如果它是平衡的,那麼它的每一層都是整個1~n區間。

所以我們可以開個陣列sor[log2(100000)][100000]記錄每層的每個小區間的排序?我知道這裡我說不太明白了,大家可以yy一下,畫畫圖,開這個東西的目的是什麼呢?就是為了在某段區間內尋找某個數排第幾,所以我們要把每個線段樹的點代表的小區間暴力排序,以便2分找。

其次呢我們還需要一個類似sor這個陣列的陣列,是記錄什麼的呢?是記錄刪除的點的!每次刪除一個點,要把這個刪除的點加到一個樹狀數組裡統計!(我說不懂了!日!我現在的內心是崩潰的!我該怎麼說好!看程式碼吧!!)

好,假設我們統計好了,然後對於每一次這個點,我們需要找他對應的位置,然後將1~k-1進行一次詢問!也就是詢問排在他前面比他大並且沒有被刪除的點的個數!這真是中心思想!剩下的自己YY!

再對k+1~n進行一次詢問,詢問比他小的並且沒有被刪除的點的個數!

最後去掉這些就好了!

反正我的程式碼是4s內的!

我不會yy出更好的方法了!

如果能有更好的方法請聯絡我!

另求hzwer這道題的解法是什麼鬼!

多yy!

程式碼:(附暴力以及資料生成器)

樹狀陣列套線段樹AC

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
typedef long long ll;
using
namespace std; int sor[35][N]; int del[35][N]; int a[N]; int s[N]; int n,m; ll tot; int lowbit(int x) { return x&(-x); } void update(int a[],int x,int v,int U) { while(x<=U) { a[x]+=v; x+=lowbit(x); } } int get_sum(int a[],int x,int D) { int ret=0; while(x>D) { ret+=a[x]; x-=lowbit(x); } return ret; } int ask_rnk(int l,int r,int rt,int v) { int ret; while(l<r) { int mid=(l+r)>>1; if(sor[rt][mid]>=v)r=mid; else l=mid+1; } if(sor[rt][l]>v)l--; return l; } void build(int l,int r,int rt) { int mid=(l+r)>>1; for(int i=l;i<=r;i++)sor[rt][i]=sor[rt-1][i]; if(l==r)return; build(l,mid,rt+1); build(mid+1,r,rt+1); sort(sor[rt]+l,sor[rt]+r+1); } void query(int l,int r,int L,int R,int v,int rt,int jd) { if(L<=l&&r<=R) { int pos=ask_rnk(l,r,rt,v); int tmp=get_sum(del[rt],pos,l-1); if(!jd) { pos=r-pos,tmp=get_sum(del[rt],r,l-1)-tmp; }else pos-=l-1; tot-=pos-tmp; return; } if(l>=r)return; int mid=(l+r)>>1; if(L<=mid)query(l,mid,L,R,v,rt+1,jd); if(R>mid)query(mid+1,r,L,R,v,rt+1,jd); } void seg_update(int l,int r,int k,int rt,int v) { if(l==r) { update(del[rt],l,1,r); return; } if(l>r)return; int mid=(l+r)>>1; if(k<=mid)seg_update(l,mid,k,rt+1,v); else seg_update(mid+1,r,k,rt+1,v); int pos=ask_rnk(l,r,rt,v); update(del[rt],pos,1,r); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&sor[0][i]); a[sor[0][i]]=i; tot+=i-1-get_sum(s,sor[0][i],0); update(s,sor[0][i],1,n); } build(1,n,1); for(int i=1;i<=m;i++) { int x; scanf("%d",&x); printf("%lld\n",tot); query(1,n,1,a[x]-1,x,1,0); query(1,n,a[x]+1,n,x,1,1); seg_update(1,n,a[x],1,x); } }

平衡樹套線段樹完美TLE(可拿去當暴力對拍)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
#define M 50100
#define K 400100
#define S 3000100
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
int n,m,size,ans;
ll tot;
int a[N];
int root[K];
int hash[N];
struct node
{
    int l,r,w,v,size,rnd;
}tr[S];
void pushup(int rt)
{
    tr[rt].size=tr[tr[rt].l].size+tr[tr[rt].r].size+tr[rt].w;
}
void lturn(int &rt)
{
    int t=tr[rt].r;
    tr[rt].r=tr[t].l;
    tr[t].l=rt;
    tr[t].size=tr[rt].size;
    pushup(rt);
    rt=t;
}
void rturn(int &rt)
{
    int t=tr[rt].l;
    tr[rt].l=tr[t].r;
    tr[t].r=rt;
    tr[t].size=tr[rt].size;
    pushup(rt);
    rt=t;
}
void insert(int &rt,int num)
{
    if(!rt)
    {
        rt=++size;
        tr[rt].w=tr[rt].size=1,tr[rt].v=num,tr[rt].rnd=rand();
        return;
    }
    tr[rt].size++;
    if(num==tr[rt].v){tr[rt].w++;return;}
    if(num<tr[rt].v){insert(tr[rt].l,num);if(tr[tr[rt].l].rnd<tr[rt].rnd)rturn(rt);}
    else {insert(tr[rt].r,num);if(tr[tr[rt].r].rnd<tr[rt].rnd)lturn(rt);}
}
void del(int &rt,int num)
{
    if(tr[rt].v==num)
    {
        if(tr[rt].w>1){tr[rt].w--,tr[rt].size--;return;}
        if(tr[rt].l*tr[rt].r==0)rt=tr[rt].l+tr[rt].r;
        else if(tr[tr[rt].l].rnd<tr[tr[rt].r].rnd){rturn(rt),del(rt,num);}
        else {lturn(rt),del(rt,num);}
    }
    else if(num<tr[rt].v){tr[rt].size--;del(tr[rt].l,num);}
    else tr[rt].size--,del(tr[rt].r,num);
}
void q_del(int k,int l,int r,int rt,int num)
{
    del(root[rt],num);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(k<=mid)q_del(k,lson,num);
    else q_del(k,rson,num);
}
void build(int l,int r,int rt,int x,int num)
{
    insert(root[rt],num);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)build(lson,x,num);
    else build(rson,x,num);
}
void tr_rnk_le(int rt,int x)
{
    if(!rt)return;
    if(tr[rt].v==x){ans+=tr[tr[rt].l].size;return;}
    else if(x<tr[rt].v){tr_rnk_le(tr[rt].l,x);}
    else {ans+=tr[tr[rt].l].size+tr[rt].w;tr_rnk_le(tr[rt].r,x);}
}
void q_rnk_le(int L,int R,int l,int r,int rt,int x)
{
    if(L==l&&r==R){tr_rnk_le(root[rt],x);return;}
    int mid=(l+r)>>1;
    if(R<=mid){q_rnk_le(L,R,lson,x);}
    else if(L>mid){q_rnk_le(L,R,rson,x);}
    else
    {
        q_rnk_le(L,mid,lson,x);
        q_rnk_le(mid+1,R,rson,x);
    }
}
void tr_rnk_bi(int rt,int x)
{
    if(!rt)return;
    if(tr[rt].v==x){ans+=tr[tr[rt].r].size;return;}
    else if(x>tr[rt].v){tr_rnk_bi(tr[rt].r,x);}
    else {ans+=tr[tr[rt].r].size+tr[rt].w;tr_rnk_bi(tr[rt].l,x);}
}
void q_rnk_bi(int L,int R,int l,int r,int rt,int x)
{
    if(L==l&&r==R){tr_rnk_bi(root[rt],x);return;}
    int mid=(l+r)>>1;
    if(R<=mid){q_rnk_bi(L,R,lson,x);}
    else if(L>mid){q_rnk_bi(L,R,rson,x);}
    else
    {
        q_rnk_bi(L,mid,lson,x);
        q_rnk_bi(mid+1,R,rson,x);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),hash[a[i]]=i;
    for(int i=1;i<=n;i++)build(1,n,1,i,a[i]);
    for(int i=1;i<n;i++)ans=0,q_rnk_le(i+1,n,1,n,1,a[i]),tot+=ans;
    for(int i=1;i<=m;i++)
    {
        printf("%lld\n",tot);
        int x;
        scanf("%d",&x);
        int y=hash[x];
        q_del(y,1,n,1,x);
        if(y!=1)ans=0,q_rnk_bi(1,y-1,1,n,1,x),tot-=ans;
        if(y!=n)ans=0,q_rnk_le(y+1,n,1,n,1,x),tot-=ans;
    }
}

資料生成器

#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
int f[100005],a[100005];
int main()
{
  srand((int)time(0));
  int n=100000,m=50000;
  printf("%d %d\n",n,m);
  for (int i=1;i<=n;i++) a[i]=i;
  int t;
  for (int i=1;i<=1000000;i++) 
  {
    int P=rand()%n+1,Q=rand()%n+1;
    t=a[P];a[P]=a[Q];a[Q]=t;
  }
  for (int i=1;i<=n;i++) printf("%d\n",a[i]);
  f[0]=1;
  for (int i=1;i<=m;i++)
  {
    for (t=0;f[t];t=rand()%n+1);
    f[t]=1;
    printf("%d\n",t);
  } 
  return 0;
}