zoukankan      html  css  js  c++  java
  • HDU7072:Boring data structure problem——题解

    https://acm.hdu.edu.cn/showproblem.php?pid=7072

    自己翻译吧(

    做法十分独特(

    比赛时满脑子线段树结果真搞出了个线段树还能过的那种(

    首先先用双端队列(删除不管)把插入全做了,同时把查询中间数转化成距离最左边元素多少个数。然后把双端队列里的数倒出来建立线段树维护区间内还活着多少个数,每次删除复杂度O(log),查询就变成了询问当前活着的数中第某个数是多少,复杂度也是O(log)。由于后两者操作个数不多,因此能够通过。

    (后面放正解,先放这个做法的代码)

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5;
    const int M=3e6+5;
    struct qry{
        int op,x,y;
    }q[M];
    deque<int>d;
    int n,b[N],c[N],tr[N<<2];
    void build(int a,int l,int r){
        if(l==r){
            tr[a]=1;return;
        }
        int mid=(l+r)>>1;
        build(a<<1,l,mid);build(a<<1|1,mid+1,r);
        tr[a]=tr[a<<1]+tr[a<<1|1];
    }
    void del(int a,int l,int r,int x){
        if(l==r){
            tr[a]=0;return; 
        }
        int mid=(l+r)>>1;
        if(x<=mid)del(a<<1,l,mid,x);
        else del(a<<1|1,mid+1,r,x);
        tr[a]=tr[a<<1]+tr[a<<1|1];
    }
    int qs(int a,int l,int r,int l1,int r1){
        if(r<l1||r1<l)return 0;
        if(l1<=l&&r<=r1)return tr[a];
        int mid=(l+r)>>1;
        return qs(a<<1,l,mid,l1,r1)+qs(a<<1|1,mid+1,r,l1,r1);
    }
    int qt(int a,int l,int r,int x){
        if(l==r)return b[l];
        int mid=(l+r)>>1;
        if(tr[a<<1]>=x)return qt(a<<1,l,mid,x);
        else return qt(a<<1|1,mid+1,r,x-tr[a<<1]);
    }
    int query(int x,int y){
        int sum=qs(1,1,n,1,y-1);
        return qt(1,1,n,sum+x);
    }
    int main(){
        int T,m=0,cnt=0;
        scanf("%d",&T);
        while(T--){
            char ch=0;
            while(ch<'A'||ch>'Z')ch=getchar();
            if(ch=='L'){
                ++m;d.push_front(++n);
            }
            if(ch=='R'){
                ++m;d.push_back(++n);
            }
            if(ch=='Q'){
                q[++cnt].op=1;q[cnt].x=ceil((double)(m+1)/2);q[cnt].y=d.front();
            }
            if(ch=='G'){
                m--;
                int x;scanf("%d",&x);
                q[++cnt].op=2;q[cnt].x=x;
            }
        }
        n=0;
        while(!d.empty()){
            b[++n]=d.front();
            d.pop_front();c[b[n]]=n;
        }
        build(1,1,n);
        for(int i=1;i<=cnt;i++){
            if(q[i].op==1){
                printf("%d
    ",query(q[i].x,c[q[i].y]));
            }
            if(q[i].op==2){
                del(1,1,n,c[q[i].x]);
            }
        }
        return 0;
    }

    正解还蛮简单的(当时有往那方面想,但是卡在不知道怎么查询上QAQ)

    维护两个链表$L$和$R$(这俩拼起来可以双端队列,这么说应该就懂了),每次要查询的时候倒一下使得两边链表大小差不多相等就好,均摊就为$O(1)$的了。删除打懒标记即可。最终复杂度全是$O(1)$的真爽。

    (跑的时间貌似和线段树差不多()

    #include<list>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5;
    list<int>L,R;
    int sL,sR,s[N];
    bool getdel(int x){return s[x]&0b01;}
    bool getwhich(int x){return s[x]&0b10;}
    int main(){
        int q,cnt=0;
        scanf("%d",&q);
        while(q--){
            char ch=0;
            while(ch<'A'||ch>'Z')ch=getchar();
            if(ch=='L'){
                ++sL;L.push_back(++cnt);
                s[cnt]=0b00;
            }
            if(ch=='R'){
                ++sR;R.push_back(++cnt);
                s[cnt]=0b10;
            }
            if(ch=='Q'){
                while(sL>sR){
                    int x=L.front();L.pop_front();
                    if(getdel(x))continue;
                    R.push_front(x);
                    --sL;++sR;s[x]|=0b10;
                }
                while(sL<=sR){
                    int x=R.front();R.pop_front();
                    if(getdel(x))continue;
                    L.push_front(x);
                    ++sL;--sR;s[x]&=0b01;
                }
                printf("%d
    ",L.front());
            }
            if(ch=='G'){
                int x;scanf("%d",&x);
                s[x]|=0b01;
                if(!getwhich(x))--sL;
                else --sR;
            }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    不喜欢数据库编程
    配置 yum 源的两种方法
    编译内核后iptables无法启动问题
    国外免费空间
    iptables--静态防火墙实例教程
    25 Most Frequently Used Linux IPTables Rules Examples
    如何开启或关闭SELinux
    google提供免费企业邮局
    RAID 0, RAID 1, RAID 5, RAID 10 Explained with Diagrams
    CentOS软件管理之fastestmirror和RPMforge
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/15153823.html
Copyright © 2011-2022 走看看