【BZOJ】【P3524】【Poi2014】【Couriers】【题解】【整体二分】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3524

最近在学整体二分

在[l,r]中出现大于(r-l+1)次的一定是(r-l+2)/2小的

求k大再判断一下出现个数是否符合

rank又一次垫底……

Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<map>
#include<vector>
using namespace std;
const int maxn=500005;
int n,m;
map<int,vector<int> >M;
struct qes{
	int x,y,z,ty,ind,cur,delta;
	qes(int _x=0,int _y=0,int _z=0,int _ty=0,int _ind=0,int _cur=0,int _delta=0):
		x(_x),y(_y),z(_z),ty(_ty),cur(_cur),delta(_delta),ind(_ind){}
}q[maxn*2];
int anss[maxn],cnt,mx,md,d[maxn];
int lowbit(int x){return x&-x;}  
int get(int x){int ans=0;while(x)ans+=d[x],x-=lowbit(x);return ans;}  
void updata(int x,int y){while(x<=n)d[x]+=y,x+=lowbit(x);}  
bool part(qes &Q){  
    if(Q.ty==2){  
        if(Q.cur+Q.delta>Q.z-1)return true;  
        Q.cur+=Q.delta;Q.delta=0;return false;  
    }return Q.y<=md;  
}  
void solve(int lef,int rig,int l,int r){  
    if(lef>rig)return;  
    if(l==r){  
        for(int i=lef;i<=rig;i++)if(q[i].ty==2){
        	int L=lower_bound(M[l].begin(),M[l].end(),q[i].x)-M[l].begin();
        	int R=upper_bound(M[l].begin(),M[l].end(),q[i].y)-M[l].begin();
        	if(R-L>(q[i].y-q[i].x+1)/2)
			anss[q[i].ind]=l;
        }return;  
    }int mid=(l+r)>>1;md=mid;  
    for(int i=lef;i<=rig;i++){  
        if(q[i].ty==1&&q[i].y<=mid)updata(q[i].x,1);   
        if(q[i].ty==2)q[i].delta=get(q[i].y)-get(q[i].x-1);  
    }for(int i=lef;i<=rig;i++)
        if(q[i].ty==1&&q[i].y<=mid)updata(q[i].x,-1);   
    int dv=stable_partition(q+lef,q+rig+1,part)-q-1;  
    solve(lef,dv,l,mid);  
    solve(dv+1,rig,mid+1,r);  
}  
int getint(){
	int res=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))res=res*10+c-'0',c=getchar();
	return res;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		int x=getint();mx=max(mx,x);
		q[++cnt]=qes(i,x,0,1);M[x].push_back(i);
	}for(int i=1;i<=m;i++){
		int l=getint(),r=getint();
		q[++cnt]=qes(l,r,(r-l+2)/2,2,++anss[0]);
	}solve(1,cnt,0,mx);
	for(int i=1;i<=anss[0];i++)printf("%d\n",anss[i]);	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值