• bzoj2653:middle


    思路:首先容易想到二分答案,但如何去check呢,对于一段区间[l,r],把所有小于答案的都赋值为-1,大于等于它的都赋值为1,然后求左端点在[a,b],右端点在[c,d]的最大子串和即可(也就是区间[a,b]的最大右子串和加上(b,c)的子串和加上区间[c,d]的最大左子串和)这样既可,用个线段树维护一下,每次暴力重建,单次询问的复杂度是完全可以承受的,但如果多次询问时间复杂度将是n^2logn,复杂度将会爆炸,因此不能每次都暴力重建,然而能作为答案的只有n个元素,也就是说线段树只可能有n种形态,不妨利用可持久化线段树先预处理出询问a[i]时的线段树的形态,这样复杂度就能少一个n,也就是nlogn的复杂度是完全可以通过本题的。至于怎么预处理,先排序,然后在预处理以a[i]为答案的线段树时显然a[i-1]是要小于a[i]的,于是就在前一棵树的基础上把a[i-1]位置上的数改为-1,新建一个root即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define maxn 20005
     
    int n,q,ans;
    int t[4],a[maxn];
     
    struct node{
        int val,pos;
        bool operator <(const node &a)const{return val<a.val;}
    }v[maxn];
    bool cmp(node a,node b){return a.pos<b.pos;}
     
    int read(){
        int x=0;int f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
     
    struct functional_segment_tree{
        int treedeg,root[maxn];
        struct treenode{
            int sum,lmax,rmax,ls,rs;
            treenode(){}
            treenode(int a,int b,int c,int d,int e){sum=a,lmax=b,rmax=c,ls=d,rs=e;}
        }tree[20*maxn];
        treenode merge(treenode a,treenode b){
            treenode ans=treenode(0,0,0,0,0);
            ans.sum=a.sum+b.sum;
            ans.lmax=max(a.lmax,a.sum+b.lmax);
            ans.rmax=max(b.rmax,b.sum+a.rmax);
            return ans;
        }
        void update(int p){
            int ls=tree[p].ls,rs=tree[p].rs;
            tree[p]=merge(tree[ls],tree[rs]);
            tree[p].ls=ls,tree[p].rs=rs;
        }
        void build(int &p,int l,int r,int val){
            p=++treedeg;int mid=(l+r)>>1;
            if (l==r){tree[p].lmax=tree[p].rmax=tree[p].sum=val;return;}
            build(tree[p].ls,l,mid,val),build(tree[p].rs,mid+1,r,val);
            update(p);
        }
        void change(int k,int &p,int l,int r,int pos,int val){
            p=++treedeg;
            if (l==r){tree[p].lmax=tree[p].rmax=tree[p].sum=val;return;}
            int mid=(l+r)>>1;
            if (pos<=mid) tree[p].rs=tree[k].rs,change(tree[k].ls,tree[p].ls,l,mid,pos,val);
            else tree[p].ls=tree[k].ls,change(tree[k].rs,tree[p].rs,mid+1,r,pos,val);
            update(p);
        }
        treenode query(int p,int l,int r,int x,int y){
            if (y<x) return treenode(0,0,0,0,0);
            if (x<=l&&r<=y) return tree[p];
            int mid=(l+r)>>1;treenode ans=treenode(0,0,0,0,0);bool flag=0;
            if (x<=mid) ans=query(tree[p].ls,l,mid,x,y),flag=1;
            if (y>mid){
                if (flag) ans=merge(ans,query(tree[p].rs,mid+1,r,x,y));
                else ans=query(tree[p].rs,mid+1,r,x,y);
            }
            return ans;
        }
    }T;
     
    bool check(int x){
        int a=T.query(T.root[x],0,n-1,t[0],t[1]).rmax;
        int b=T.query(T.root[x],0,n-1,t[1]+1,t[2]-1).sum;
        int c=T.query(T.root[x],0,n-1,t[2],t[3]).lmax;
        return a+b+c>=0;
    }
     
    int main(){
        n=read();
        for (int i=0;i<n;i++) a[i]=read(),v[i].val=a[i],v[i].pos=i;
        sort(v,v+n),T.build(T.root[0],0,n-1,1);
        for (int i=1;i<n;i++) T.change(T.root[i-1],T.root[i],0,n-1,v[i-1].pos,-1);
        q=read();
        while (q--){
            for (int i=0;i<4;i++) t[i]=(read()+ans)%n;sort(t,t+4);
            int l=0,r=n-1;
            while (l<r){
                int mid=(l+r)>>1;
                if (check(mid+1)) l=mid+1;
                else r=mid;
            }
            printf("%d
    ",ans=v[l].val);
        }
        return 0;
    }
    
  • 相关阅读:
    反射
    接口和抽象类
    套接字通信
    C#的urlencode
    go语言摘记
    c# Httphelper帮助类 简约版
    maven
    读取资源文件里的值---来源practical-aspnetcore项目
    JWT使用---来源practical-aspnetcore项目
    .net core国际化
  • 原文地址:https://www.cnblogs.com/DUXT/p/6007690.html
Copyright © 2020-2023  润新知