Hdu 5193 Go to movies Ⅱ(帶刪除數插入數的逆序數對,塊狀鏈表)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

傳送門:Hdu 5193 Go to movies Ⅱ

題意:
有n個人站成一排,每個人的身高為Hi。每次有人加入或者有人離開,就要判斷有多少人站反了(i < j&&Hi>Hj)
第一行n,m,接下來n個整數(n,m<=2e4)
接下來m行,
0 x y 表示有一個身高為y的人插在x後面,x=0表示插在最前面。(1≤y≤n)
1 x 表示第x個人(從左至右)離開。

思路:摘自題解http://bestcoder.hdu.edu.cn/solutions.php?page=12
添加或者刪除一個元素時,維護逆序對時,需要知道在它之前有多少個數比它大,在它之後有多少個數比他小。有下標和權值兩個維度,可以使用兩個資料結構嵌套。題目中n=20000,範圍不大,外層可以使用分塊維護下標,這樣添加和刪除元素的時候,
也很方便,直接暴力。尋找權值個數時,使用樹狀數組比較方便。內層通過樹狀數組維護權值。設每塊的大小為S,那麼刪除或者添加元素時,維護逆序對數的複雜度是O(S+P∗logn),S是塊內直接暴力更新逆序對的代價,
P/S∗logn在前面塊找比它大和在後面塊中找比它小的代價,P表示當前元素的個數。為了使這兩部分複雜度盡量均攤讓S=P/S∗logn,S取根號Plogn
。直接通過分塊暴力添加和刪除時,塊的大小會退化,需要重構,。重構一次的複雜度是S*logn, 總的重構複雜度是,與添加和刪除總的複雜度一至。因此整個問題的複雜度為O(m√nlogn).

#include<bits/stdc++.h>using namespace std;const int maxn=20010;const int MAX_S=1050;int ans,tot,n;void add(int *c,int x,int v){    while(x<=n){        c[x]+=v;        x+=(x&-x);    }}int sum(int *c,int x){    int ret=0;    while(x>0){        ret+=c[x];        x-=(x&-x);    }    return ret;}struct node_t{    int num[MAX_S+10],sz,c[maxn],next,pre;    void init(){        memset(c,0,sizeof(c));        sz=0;        pre=0;        next=0;    }}b[310];int get_pos(int &x){    int i=1;    while(b[i].sz<x&&b[i].next)        x-=b[i].sz,i=b[i].next;    return i;}int cal(int x){    int ret=0;    int id=get_pos(x);    for(int i=1;i<x;i++)            if(b[id].num[i]>b[id].num[x])            ret++;    for(int i=x+1;i<=b[id].sz;i++)        if(b[id].num[i]<b[id].num[x])            ret++;    for(int i=1;i!=id;i=b[i].next)        ret+=sum(b[i].c,n)-sum(b[i].c,b[id].num[x]);    for(int i=b[id].next;i!=0;i=b[i].next)        ret+=sum(b[i].c,b[id].num[x]-1);    return ret;}int flag;void ins(int x){    int y=x;    if(flag==0){    //是不是第一個元素          b[1].init();        scanf("%d",&b[1].num[++b[1].sz]);        add(b[1].c,b[1].num[1],1);        flag=1;        return ;    }    int id=get_pos(x);      //id表示在哪一塊中    if(b[id].sz==MAX_S){    //塊重構        b[++tot].init(),b[id].sz++;        int cnt=0;        for(int i=b[id].sz;i>x;i--)            b[id].num[i]=b[id].num[i-1];        scanf("%d",&b[id].num[x]);        add(b[id].c,b[id].num[x],1);        int len=b[id].sz/2;        for(int i=len+1;i<=b[id].sz;i++){            b[tot].num[++cnt]=b[id].num[i];            add(b[tot].c,b[id].num[i],1);            add(b[id].c,b[id].num[i],-1);        }        b[tot].sz=cnt,b[tot].next=b[id].next;        b[id].next=tot,b[id].sz=len;        b[tot].pre=id;    }    else{        b[id].sz++;        for(int i=b[id].sz;i>x;i--)            b[id].num[i]=b[id].num[i-1];        scanf("%d",&b[id].num[x]);        add(b[id].c,b[id].num[x],1);    }    ans+=cal(y);}void del(int x){    ans-=cal(x);    int id=get_pos(x);    add(b[id].c,b[id].num[x],-1);    for(int i=x+1;i<=b[id].sz;i++)        b[id].num[i-1]=b[id].num[i];    b[id].sz--;    if(b[id].sz==0){    //刪除塊          int pre=b[id].pre,net=b[id].next;        b[net].pre=pre;        b[pre].next=net;    }}int main(){    int m,op,x,y;    while(~scanf("%d%d",&n,&m)){        ans=0,tot=1,b[1].sz=0,flag=0;        for(int i=1;i<=n;i++)            ins(i);        for(int i=1;i<=m;i++){            scanf("%d",&op);            if(op==0){                scanf("%d",&x);                ins(x+1);            }            else{                scanf("%d",&x);                del(x);            }            printf("%d\n",ans);        }    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.