• [国家集训队]middle


    题目

    洛谷

    做法

    完全把主席树当作线段树维护

    有一种经典的办法:二分+变化数列
    一个数列中(a[i]<x)则为(0)否则为(1),只有这个数列的和(≥0)才成立,二分值域就好了
    通俗易懂地说((l,r,x):sumlimits{i=l}^r[a[i]≥x]≥sumlimits{i=l}^r [a[i]<x])

    位置一排,值域线段树似乎不好做;但转换一下,值域一排,普通线段树就容易多了

    至于(([a,b][c,d]))这两段,后/前缀最大子序列就好了,毕竟烂大街的操作就不讲了

    My complete code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL maxn=1e7;
    inline LL Read(){
    	LL x(0),f(1); char c=getchar();
    	while(c<'0' || c>'9'){ if(c=='-')c=-1; c=getchar(); }
    	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    struct node{
    	LL val,x;
    	bool operator < (const node &b)const{
    		return val<b.val;
    	}
    }a[maxn];
    LL n,q,nod,lst;
    LL son[maxn][2],lx[maxn],rx[maxn],sum[maxn],root[maxn],tmp[10];
    inline void Update(LL now){
    	LL lc(son[now][0]),rc(son[now][1]);
    	sum[now]=sum[lc]+sum[rc];
    	lx[now]=max(lx[lc],sum[lc]+lx[rc]),
    	rx[now]=max(rx[rc],sum[rc]+rx[lc]);
    }
    void Build(LL &now,LL l,LL r){
    	now=++nod;
    	if(l==r){
    		lx[now]=rx[now]=sum[now]=1;
    		return;
    	}
    	LL mid(l+r>>1);
    	Build(son[now][0],l,mid), Build(son[now][1],mid+1,r);
    	Update(now);
    }
    void Merge(LL &now,LL pre,LL l,LL r,LL c){
    	now=++nod;
    	if(l==r){
    		lx[now]=rx[now]=sum[now]=-1; return;
    	} 
    	LL mid(l+r>>1);
    	if(c<=mid) Merge(son[now][0],son[pre][0],l,mid,c), son[now][1]=son[pre][1];
    	else Merge(son[now][1],son[pre][1],mid+1,r,c), son[now][0]=son[pre][0];
    	Update(now);
    }
    LL Query_sum(LL now,LL l,LL r,LL lt,LL rt){
    	if(lt<=l && rt>=r) return sum[now];
    	LL mid(l+r>>1),ret(0);
    	if(lt<=mid) ret+=Query_sum(son[now][0],l,mid,lt,rt);
    	if(rt>mid) ret+=Query_sum(son[now][1],mid+1,r,lt,rt);
    	return ret;
    }
    LL Query_rsum(LL now,LL l,LL r,LL lt,LL rt){
    	if(lt<=l && rt>=r) return rx[now];
    	LL mid(l+r>>1);
    	if(lt>=mid+1) return Query_rsum(son[now][1],mid+1,r,lt,rt);
    	else if(rt<=mid) return Query_rsum(son[now][0],l,mid,lt,rt);
    	else return max(Query_rsum(son[now][1],mid+1,r,lt,rt),Query_rsum(son[now][0],l,mid,lt,rt)+Query_sum(son[now][1],mid+1,r,lt,rt));
    }
    LL Query_lsum(LL now,LL l,LL r,LL lt,LL rt){
    	if(lt<=l && rt>=r) return lx[now];
    	LL mid(l+r>>1);
    	if(lt>=mid+1) return Query_lsum(son[now][1],mid+1,r,lt,rt);
    	else if(rt<=mid) return Query_lsum(son[now][0],l,mid,lt,rt);
    	else return max(Query_lsum(son[now][0],l,mid,lt,rt),Query_lsum(son[now][1],mid+1,r,lt,rt)+Query_sum(son[now][0],l,mid,lt,rt));
    }
    inline LL Check(LL l1,LL r1,LL l2,LL r2,LL mid){
    	LL sum(0);
    	if(r1+1<=l2-1) sum+=Query_sum(root[mid],1,n,r1+1,l2-1);
    	sum+=Query_rsum(root[mid],1,n,l1,r1);
    	sum+=Query_lsum(root[mid],1,n,l2,r2);
    	return sum>=0;
    }
    inline LL Solve(LL l1,LL r1,LL l2,LL r2){
    	LL l(1),r(n),ans(0);
    	while(l<=r){
    		LL mid(l+r>>1);
    		if(Check(l1,r1,l2,r2,mid)) l=mid+1,ans=mid;
    		else r=mid-1;
    	}return ans;
    }
    int main(){
    	n=Read();
    	for(LL i=1;i<=n;++i) a[i]=(node){Read(),i};
    	sort(a+1,a+1+n);
    	Build(root[1],1,n);
    	for(LL i=2;i<=n;++i)
    	    Merge(root[i],root[i-1],1,n,a[i-1].x);
    	q=Read();
    	while(q--){
    		LL a1(Read()),b1(Read()),c1(Read()),d1(Read());
    		tmp[1]=(a1+lst)%n+1,tmp[2]=(b1+lst)%n+1,tmp[3]=(c1+lst)%n+1,tmp[4]=(d1+lst)%n+1;
    		sort(tmp+1,tmp+5);
    		printf("%lld
    ",lst=a[Solve(tmp[1],tmp[2],tmp[3],tmp[4])].val);
    	}return 0;
    }
    
  • 相关阅读:
    【贪心】时空定位I
    【贪心】删数问题
    【贪心】取火柴游戏
    【贪心】均分纸牌
    Fix a Tree
    Vacations
    One Bomb
    Abandoned country
    BZOJ 1006 [HNOI2008]神奇的国度
    BZOJ 2118 墨墨的等式
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10403041.html
Copyright © 2020-2023  润新知