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();}
    
  • 相关阅读:
    对象池使用时要注意几点
    Flash3D学习计划(一)——3D渲染的一般管线流程
    714. Best Time to Buy and Sell Stock with Transaction Fee
    712. Minimum ASCII Delete Sum for Two Strings
    647. Palindromic Substrings(马拉车算法)
    413. Arithmetic Slices
    877. Stone Game
    338. Counting Bits
    303. Range Sum Query
    198. House Robber
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15135635.html
Copyright © 2011-2022 走看看