[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\n",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
posted @ 2019-02-03 01:50  wang9897  阅读(193)  评论(0编辑  收藏  举报