zoukankan      html  css  js  c++  java
  • BZOJ 1171: 大sz的游戏

    ZJOI讲课的题目,数据结构什么的还是很友好的说

    首先我们发现题目中提到的距离(le L)的东西显然可以用单调队列维护

    但是暴力搞去不掉区间并的限制,那么我们考虑从区间并入手

    对于这种问题的套路有一个就是线段树维护一个区间的最优解,然后计算完一个点的答案之后直接在线段树上更新即可

    所以我们有了一个很naive的思路——线段树套单调队列,但随便一想时空复杂度都是(O(n^2))

    让我们想一下复杂度变大的原因是什么,其实就是pushdown带来的大量空间浪费

    我们再仔细观察依稀这个问题的性质,发现其可以标记永久化,那么就很舒服了,时空复杂度都达到了优秀的(O(nlog n))

    然后像我这样naive的人就写出了这样的巨慢CODE

    #include<cstdio>
    #include<cctype>
    #include<deque>
    #include<algorithm>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=250005,INF=2e9;
    int n,m,rst[N<<1],L[N],R[N],ans[N],dis[N],cnt,ret;
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            Tp inline void write(T x)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); if (x<0) x=-x,pc('-'); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef tc
            #undef pc
    }F;
    inline int find(CI x)
    {
        return lower_bound(rst+1,rst+cnt+1,x)-rst;
    }
    class Segment_Tree
    {
        private:
            deque <int> dq[N<<3];
        public:
            #define TN CI now=1,CI l=1,CI r=cnt
            #define O beg,end,pos
            inline void build(TN)
            {
                dq[now].push_back(1); if (l==r) return; int mid=l+r>>1;
                build(now<<1,l,mid); build(now<<1|1,mid+1,r);
            }
            inline void insert(CI beg,CI end,CI pos,TN)
            {
                while (!dq[now].empty()&&ans[pos]<ans[dq[now].back()]) dq[now].pop_back();
                dq[now].push_back(pos); if (l==r) return; int mid=l+r>>1;
                if (beg<=mid) insert(O,now<<1,l,mid); if (end>mid) insert(O,now<<1|1,mid+1,r);
            }
            inline void getpos(CI beg,CI end,CI pos,TN)
            {
                if (beg<=l&&r<=end)
                {
                    while (!dq[now].empty()&&dis[pos]-dis[dq[now].front()]>m) dq[now].pop_front();
                    if (!dq[now].empty()&&(!~ret||ans[dq[now].front()]<ans[ret]))    ret=dq[now].front(); return;
                }
                int mid=l+r>>1; if (beg<=mid) getpos(O,now<<1,l,mid); if (end>mid) getpos(O,now<<1|1,mid+1,r);
            }
            #undef TN
            #undef O
    }SEG;
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i; for (F.read(n),F.read(m),i=2;i<=n;++i)
        F.read(L[i]),F.read(R[i]),rst[++cnt]=L[i],rst[++cnt]=R[i],F.read(dis[i]);
        sort(rst+1,rst+cnt+1); cnt=unique(rst+1,rst+cnt+1)-rst-1;
        for (i=2;i<=n;++i) L[i]=find(L[i]),R[i]=find(R[i]);
        for (SEG.build(),i=2;i<=n;++i)
        {
            ret=-1; SEG.getpos(L[i],R[i],i); if (!~ret) ans[i]=INF;
            else ans[i]=ans[ret]+1; SEG.insert(L[i],R[i],i);
        }
        for (i=2;i<=n;++i) F.write(ans[i]!=INF?ans[i]:-1); return F.Fend(),0;
    }
    

    没办法,我们发现这个程序慢有两点:

    • deque巨慢无比,而且内存占用极大
    • 没有维护每个节点的答案,这样查询的时候复杂度极高

    然后解决方案也很简单:

    • deque换成list(快如闪电)
    • 单独写删除操作,并且记下每个点的答案

    然后就可以顺利地通过此题了QWQ

    #include<cstdio>
    #include<cctype>
    #include<list>
    #include<algorithm>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=250005,INF=1e9;
    int n,m,rst[N<<1],q[N],L[N],R[N],dis[N],ans[N],cnt,pos;
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            Tp inline void write(T x)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); if (x<0) x=-x,pc('-'); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef tc
            #undef pc
    }F;
    inline int find(CI x)
    {
        return lower_bound(rst+1,rst+cnt+1,x)-rst;
    }
    class Segment_Tree
    {
        private:
            list <int> dq[N<<3]; int val[N<<3];
            inline void miner(int &x,CI y)
            {
                if (y<x) x=y;
            }
            inline int get(CI now)
            {
                if (dq[now].empty()) return INF; return ans[dq[now].front()];
            }
            inline void pushup(CI now,const bool& op)
            {
                val[now]=get(now); if (op) miner(val[now],val[now<<1]),miner(val[now],val[now<<1|1]);
            }
        public:
            #define TN CI now=1,CI l=1,CI r=cnt
            #define O beg,end,pos
            inline void build(TN)
            {
                val[now]=INF; if (l==r) return; int mid=l+r>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r);
            }
            inline void insert(CI beg,CI end,CI pos,TN)
            {
                if (beg<=l&&r<=end)
                {
                    while (!dq[now].empty()&&ans[pos]<=ans[dq[now].back()])
                    dq[now].pop_back(); dq[now].push_back(pos); return pushup(now,l!=r);
                }
                int mid=l+r>>1; if (beg<=mid) insert(O,now<<1,l,mid);
                if (end>mid) insert(O,now<<1|1,mid+1,r); pushup(now,l!=r);
            }
            inline void remove(CI beg,CI end,CI pos,TN)
            {
                if (beg<=l&&r<=end)
                {
                    while (!dq[now].empty()&&dq[now].front()<=pos)
                    dq[now].pop_front(); return pushup(now,l!=r);
                }
                int mid=l+r>>1; if (beg<=mid) remove(O,now<<1,l,mid);
                if (end>mid) remove(O,now<<1|1,mid+1,r); pushup(now,l!=r);
            }
            inline int query(CI beg,CI end,TN)
            {
                if (beg<=l&&r<=end) return val[now]; int mid=l+r>>1,ret=get(now);
                if (beg<=mid) miner(ret,query(beg,end,now<<1,l,mid));
                if (end>mid) miner(ret,query(beg,end,now<<1|1,mid+1,r)); return ret;
            }
            #undef TN
            #undef O
    }SEG;
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i,H=1,T=1; for (F.read(n),F.read(m),i=2;i<=n;++i)
        F.read(L[i]),F.read(R[i]),rst[++cnt]=L[i],rst[++cnt]=R[i],F.read(dis[i]);
        sort(rst+1,rst+cnt+1); cnt=unique(rst+1,rst+cnt+1)-rst-1;
        for (i=2;i<=n;++i) L[i]=find(L[i]),R[i]=find(R[i]);
        for (SEG.build(),SEG.insert(L[1]=q[1]=1,R[1]=cnt,1),i=2;i<=n;++i)
        {
            while (H<=T&&dis[i]-dis[q[H]]>m) pos=q[H++],SEG.remove(L[pos],R[pos],pos);
            ans[i]=SEG.query(L[i],R[i]); if (ans[i]!=INF)
            F.write(++ans[i]),SEG.insert(L[i],R[i],i),q[++T]=i; else F.write(-1);
        }
        return F.Fend(),0;
    }
    
  • 相关阅读:
    7月15日考试 题解(链表+状压DP+思维题)
    暑假集训日记
    C# .NET 使用 NPOI 生成 .xlsx 格式 Excel
    JavaSE 基础 第42节 局部内部类
    JavaSE 基础 第41节 匿名内部类
    JavaSE 基础 第40节 内部类概述
    JavaSE 基础 第39节 接口的应用
    JavaSE 基础 第38节 接口的实现
    JavaSE 基础 第37节 接口概述
    JavaSE 基础 第36节 抽象类概述与使用
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10673063.html
Copyright © 2011-2022 走看看