zoukankan      html  css  js  c++  java
  • NOIP 模拟 $36; m Cicada 拿衣服$

    题解 (by;zjvarphi)

    发现右端点固定时,左端点的 (min-max) 单调递减,且对于 (or)(and) 相减,最多有 ( m2logn)个不同的值,且相同的值构成一段连续的区间。

    那么就可以在最远的,符合答案的第一个区间二分答案。

    具体实现可以用一个链表,每次扫一遍合并,并倒着查合法区间,这样就能做到 ( m nlogn)

    Code
    #include<bits/stdc++.h>
    #define ri register signed
    #define Re register
    #define p(i) ++i
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
        struct nanfeng_stream{
            template<typename T>inline nanfeng_stream operator>>(T &x) {
                ri f=0;x=0;register char ch=gc();
                while(!isdigit(ch)) f|=ch=='-',ch=gc();
                while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
                return x=f?-x:x,*this;
            }
        }cin;
    }
    using IO::cin;
    namespace nanfeng{
        #define node(x,y,z) (node){x,y,z}
        #define eb emplace_back
        #define FI FILE *IN
        #define FO FILE *OUT
        template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
        template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
        static const int N=1e6+7;
        struct node{int l,OR,AND;int val() {return OR-AND;}};
        std::list<node> lis;
        int a[N],stn[N][23],stx[N][23],lg[N],n,k;
        inline void init_rmq() {
            for (ri i(1);i<=n;p(i)) stx[i][0]=stn[i][0]=a[i];
            for (ri i(2);i<=n;p(i)) lg[i]=lg[i>>1]+1;
            for (ri j(1);j<19;p(j)) {
                ri len=1<<j;
                for (ri i(1);i+len-1<=n;p(i)) {
                    stx[i][j]=cmax(stx[i][j-1],stx[i+(1<<j-1)][j-1]);
                    stn[i][j]=cmin(stn[i][j-1],stn[i+(1<<j-1)][j-1]);
                }
            }
        }
        inline int Getmx(int l,int r) {
            int k=lg[r-l+1];
            return cmax(stx[l][k],stx[r-(1<<k)+1][k]);
        }
        inline int Getmn(int l,int r) {
            int k=lg[r-l+1];
            return cmin(stn[l][k],stn[r-(1<<k)+1][k]);
        }
        inline bool check(Re std::list<node>::iterator it,int l,int r) {return it->val()+Getmn(l,r)-Getmx(l,r)>=k;}
        struct Seg{
            #define ls(x) (x<<1)
            #define rs(x) (x<<1|1)
            struct segmenttree{int mx,lz;segmenttree(){mx=lz=-1;}}T[N<<2];
            inline void down(int x) {
                int l=ls(x),r=rs(x);
                T[l].mx=cmax(T[l].mx,T[x].lz);
                T[r].mx=cmax(T[r].mx,T[x].lz);
                T[l].lz=cmax(T[l].lz,T[x].lz);
                T[r].lz=cmax(T[r].lz,T[x].lz);
            }  
            void update(int x,int l,int r,int lt,int rt) {
                if (l<=lt&&rt<=r) {
                    T[x].lz=cmax(T[x].lz,r-l+1);
                    T[x].mx=cmax(T[x].mx,r-l+1);
                    return;
                }
                down(x);
                int mid(lt+rt>>1);
                if (l<=mid) update(ls(x),l,r,lt,mid);
                if (r>mid) update(rs(x),l,r,mid+1,rt);
            }
            void print(int x,int l,int r) {
                if (l==r) return (void)(printf("%d ",T[x].mx));
                int mid(l+r>>1);
                down(x);
                print(ls(x),l,mid);
                print(rs(x),mid+1,r);
            }
        }T;
        inline int main() {
            //FI=freopen("nanfeng.in","r",stdin);
            //FO=freopen("nanfeng.out","w",stdout);
            cin >> n >> k;
            for (ri i(1);i<=n;p(i)) cin >> a[i];
            init_rmq();
            for (ri i(1);i<=n;p(i)) {
                for (Re auto it=lis.begin();it!=lis.end();p(it)) it->OR|=a[i],it->AND&=a[i];
                lis.eb(node(i,a[i],a[i]));
                for (Re auto it1=lis.begin(),it2=next(it1);it2!=lis.end();p(it2)) 
                    if (it1->val()==it2->val()) lis.erase(it1),it1=it2;
                    else p(it1);
                for (Re auto it=lis.begin();it!=lis.end();p(it)) 
                    if (check(it,it->l,i)) {
                        ri l=1,r=it->l,res;
                        if (it!=lis.begin()) l=prev(it)->l+1;
                        while(l<=r) {
                            int mid(l+r>>1);
                            if (check(it,mid,i)) r=mid-1,res=mid;
                            else l=mid+1;
                        }
                        T.update(1,res,i,1,n);                     
                        break;
                    }
            }
            T.print(1,1,n);
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    
  • 相关阅读:
    MT【347】单变量求最值
    MT【346】拐点处分界
    MT【345】三个绝对值的和
    MT【344】构造函数
    MT【343】三数平方法
    MT【342】条件为非负实数
    MT【341】换元变形
    MT【340】彭塞列闭合定理
    MT【339】待定系数
    MT【338】分式变形
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15135635.html
Copyright © 2011-2022 走看看