hdu 6621 hdu多校第四场1008

线段树每个结点维护一个有序序列。。。合并两个区间用归并排序维护有序性。

查询时查询  区间L-R中值为x-y之间数的个数。8000多ms

也可以用主席树维护   3000多ms。。

然后以数值p为中点,往两边扩展d。。这个d具有单调性  可二分。

如果p-d   --  p+d 区间数刚好K个 那么  d就是答案。。(第K小的   p-a[i]的距离)

复杂度nlog^2n

#include<bits/stdc++.h>
#define ls o<<1
#define rs o<<1|1
#define mm (l+r)/2
using namespace std;
const int M=100000+77;
vector<int> v[M*25];
int a[M<<2];
void build(int o,int l,int r)
{
	v[o].clear();
	if(l==r)
	{
		v[o].push_back(a[l]);
		return ;
	}
	build(ls,l,mm);
	build(rs,mm+1,r);
	int i=0,j=0;
	int nl=v[ls].size();
	int nr=v[rs].size();
	while(i<nl&&j<nr)
	{
		if(v[ls][i]<=v[rs][j])
		{
			v[o].push_back(v[ls][i]);
			i++;
		}
		else
		{
			v[o].push_back(v[rs][j]);
			j++;
		}
	}
	while(i<nl)
	{
		v[o].push_back(v[ls][i]);
		i++;
	}
	while(j<nr)
	{
		v[o].push_back(v[rs][j]);
		j++;
	}
}
int query(int o,int l,int r,int L,int R,int x,int y)//L-R区间  值为x-y之间的数的个数 
{
	if(x>y)return 0;
	if(L<=l&&r<=R)
	{
		return upper_bound(v[o].begin(),v[o].end(),y)-lower_bound(v[o].begin(),v[o].end(),x);
	}
	int res=0;
	if(L<=mm)res+=query(ls,l,mm,L,R,x,y);
	if(R>mm)res+=query(rs,mm+1,r,L,R,x,y);
	return res;
} 
int main()
{
	int X,N,M,T,L,R,p,K;
	scanf("%d",&T);
    while(T--)
	{
		X=0;
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]);
        build(1,1,N);
        while(M--)
		{
            scanf("%d%d%d%d",&L,&R,&p,&K);
            L^=X,R^=X,p^=X,K^=X;
            int l=0,r=1000000+7,mid,pos=r;
            while(l<=r)
	        {
	        	mid=(l+r)/2; 
	        	if(query(1,1,N,L,R,p-mid,p+mid)>=K)
	        	{
	        		r=mid-1;
	        		pos=mid;
				}
				else
				{
					l=mid+1;
				}
			}
			X=pos;
			printf("%d\n",X);
        } 
    }
	return 0;
 } 
 /*
 1
5 1
31 2 5 45 4
1 5 5 1
 */

主席树写法

#include<bits/stdc++.h>
#define ls o<<1
#define rs o<<1|1
#define mm (l+r)/2
using namespace std;
const int M=1e6+77;
struct node
{
    int sum,l,r;
}T[M*25];
int a[M],root[M];
int now;
void update(int l,int r,int &x,int y,int pos)
{
    T[++now]=T[y],T[now].sum++,x=now;
    if(l==r)return ;
    int mid=(l+r)/2;
    if(mid>=pos)update(l,mid,T[x].l,T[y].l,pos);
    else update(mid+1,r,T[x].r,T[y].r,pos);
}
int c(int l,int r,int x,int y,int L,int R){
    if(l>=L&&R>=r)return T[y].sum-T[x].sum;
    int mid=l+r>>1;
    int ans=0;
    if(L<=mid)ans+=c(l,mid,T[x].l,T[y].l,L,R);
    if(R>mid)ans+=c(mid+1,r,T[x].r,T[y].r,L,R);
    return ans;
}
int main()
{
    int X,N,M,t,L,R,p,K;
    scanf("%d",&t);
    while(t--)
    {
        X=0,now=0;
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]);
        for(int i=1;i<=N;i++)update(1,1000000,root[i],root[i-1],a[i]);
        while(M--)
        {
            scanf("%d%d%d%d",&L,&R,&p,&K);
            L^=X,R^=X,p^=X,K^=X;
            int l=0,r=1000000+7,mid,pos=r;
            while(l<=r)
            {
                mid=(l+r)/2; 
                if(c(1,1000000,root[L-1],root[R],p-mid,p+mid)>=K)
                {
                    r=mid-1;
                    pos=mid;
                }
                else
                {
                    l=mid+1;
                }
            }
            X=pos;
            printf("%d\n",X);
        } 
    }
    return 0;
 } 
 /*
 1
5 1
31 2 5 45 4
1 5 5 1
 */

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值