zoukankan      html  css  js  c++  java
  • [BZOJ]2653: middle

    题解:神.....神题

    求中位数->区间第k大->主席树  好了进死胡同了  因为没办法差分区间和区间

    我们再考虑  对于中位数...那我们把大于等于这个数的置1 小于这个数置-1  然后查询区间和是否大于等于0来check  根据这个性质 我们考虑二分中位数(因为具有单调性...很明显证明

    但是每次二分都去修改序列 复杂度太高接受不了 我们考虑用主席树优化  记录把某个位置置为-1后维护各个历史版本的信息 然后类似于区间合并 维护各个版本情况下 从区间左端点最大连续和  右端点最大连续和 然后check即可

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    typedef struct node{
        int l,r,lnum,rnum,sum;
    }node;
    
    node d[MAXN*21];int cnt;
    int rt[MAXN],a[MAXN];
    
    void up(int x){
        d[x].sum=d[d[x].l].sum+d[d[x].r].sum;
        d[x].lnum=max(d[d[x].l].lnum,d[d[x].l].sum+d[d[x].r].lnum);
        d[x].rnum=max(d[d[x].r].rnum,d[d[x].r].sum+d[d[x].l].rnum);
    }
    
    void built(int &x,int l,int r){
        x=++cnt;
        if(l==r){d[x].lnum=d[x].rnum=d[x].sum=1;return ;}
        int mid=(l+r)>>1;
        built(d[x].l,l,mid);
        built(d[x].r,mid+1,r);
        up(x);
    }
    
    void update(int &x,int y,int l,int r,int t){
        x=++cnt;d[x]=d[y];
        if(l==r){d[x].lnum=d[x].rnum=0;d[x].sum=-1;return ;}
        int mid=(l+r)>>1;
        if(t<=mid)update(d[x].l,d[y].l,l,mid,t);
        else update(d[x].r,d[y].r,mid+1,r,t);
        up(x);
    }
    
    int ans1;
    void query1(int x,int l,int r,int ql,int qr){
        if(!x)return ;
        if(ql<=l&&r<=qr){ans1+=d[x].sum;return ;}
        int mid=(l+r)>>1;
        if(ql<=mid)query1(d[x].l,l,mid,ql,qr);
        if(qr>mid)query1(d[x].r,mid+1,r,ql,qr);
    }
    
    node ans2;
    void query2(int x,int l,int r,int ql,int qr){
        if(!x)return ;
        if(ql<=l&&r<=qr){
    	ans2.lnum=max(ans2.lnum,ans2.sum+d[x].lnum);
    	ans2.rnum=max(d[x].rnum,d[x].sum+ans2.rnum);
    	ans2.sum+=d[x].sum;
    	return ;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)query2(d[x].l,l,mid,ql,qr);
        if(qr>mid)query2(d[x].r,mid+1,r,ql,qr);
    }
    
    typedef struct Node{
        int id,k;
        friend bool operator<(Node aa,Node bb){return aa.k<bb.k;}
    }Node;
    Node que[MAXN];
    int q[4],n;
    
    bool check(int t){
        //cout<<t<<"===="<<endl;
        t--;
        ans1=0;query1(rt[t],1,n,q[1],q[2]);
       // cout<<ans1<<endl;
        ans2.lnum=ans2.rnum=ans2.sum=0;
        query2(rt[t],1,n,q[0],q[1]-1);ans1+=ans2.rnum;
        //cout<<ans2.lnum<<" "<<ans2.rnum<<" "<<ans2.sum<<endl;
        ans2.lnum=ans2.rnum=ans2.sum=0;
        query2(rt[t],1,n,q[2]+1,q[3]);ans1+=ans2.lnum;
        //cout<<ans2.lnum<<" "<<ans2.rnum<<" "<<ans2.sum<<endl;
        //cout<<ans1<<endl;
        if(ans1>=0)return 1;
        return 0;
    }
    
    int main(){
        n=read();
        inc(i,1,n)que[i].k=read(),que[i].id=i;
        sort(que+1,que+n+1);
        built(rt[0],1,n);
        inc(i,1,n)update(rt[i],rt[i-1],1,n,que[i].id);
        int lastAns=0;
        int m=read();
        while(m--){
    	inc(i,0,3)q[i]=(read()+lastAns)%n+1;
    	sort(q,q+4);
    	//inc(i,0,3)cout<<q[i]<<" ";
    	//cout<<endl;
    	int l=1;int r=n;int ans=0;
    	while(l<=r){
    	    int mid=(l+r)>>1;
    	    if(check(mid))ans=mid,l=mid+1;
    	    else r=mid-1;
    	}
    	lastAns=que[ans].k;
    	printf("%d
    ",lastAns);
        }
        return 0;
    }
    

      

    2653: middle

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 2721  Solved: 1547
    [Submit][Status][Discuss]

    Description

    一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
    长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
    其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

    Input

    第一行序列长度n。接下来n行按顺序给出a中的数。
    接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
    x(如果这是第一个询问则x=0)。
    令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
    将q从小到大排序之后,令真正的
    要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
    输入保证满足条件。
    第一行所谓“排过序”指的是从小到大排序!
    n<=20000,Q<=25000
     

    Output

    Q行依次给出询问的答案。

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0

    Sample Output

    271451044
    271451044
    969056313
  • 相关阅读:
    The hardest problem ever
    1146 Topological Order
    1147 Heaps
    Weekly Contest 184
    1148 Werewolf
    1149 Dangerous Goods Packaging
    1150 Travelling Salesman Problem
    1151 LCA in a Binary Tree (30point(s))
    1152 Google Recruitment
    美团2020春招笔试
  • 原文地址:https://www.cnblogs.com/wang9897/p/10349541.html
Copyright © 2011-2022 走看看