• 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;
    }
    
  • 相关阅读:
    杂记
    asp.net preview 5 bug[转]
    jquery笔记
    北京互联网创业团队诚邀英才加盟
    伊瓜苏大瀑布
    log4net udp组件的应用
    Mock介绍
    自写的BackgroundWorker的学习例子
    RegexBuddy使用例子,及Visual Studio中正则使用的请教
    TestDriven.NET2.14.2190(not RTM) last update at 2008723
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10673063.html
Copyright © 2020-2023  润新知