zoukankan      html  css  js  c++  java
  • 【JZOJ3379】查询

    description

    对于一个整数序列,查询区间第k大数可以在O(logN)的时间内轻松完成。现在我们对这个问题进行推广。

    考虑带重复数的集合(multiset)。定义在该类集合上的并操作“+”为两个集合的所有数不剔除重复得到的结果。比如,若A={1,2,2,3},B={2,3,4,4},则C={1,2,2,2,3,3,4,4}。

    对于一个给定序列A[1..N],定义A[x..y]为包含y-x+1个元素的集合{A[x],A[x+1],…,A[y]}。现在,给定整数序列A,你需要回答很多询问,其中第i个询问要求集合A[x[i,1]..y[i,1]]+A[x[i,2]..y[i,2]]+…+A[x[i,ki]..y[i,ki]]中第pi小的元素。


    analysis

    • 一年的时间使我变成了主席树傻子

    • 一个区间当然可以直接主席树做,五个区间其实也可以

    • (a)的值并不是很大,不需要离散化

    • 对于当前查询,可以求出五个区间左儿子区间里面数的个数之和,然后和查询值比较

    • 然后向左或右儿子继续二分,把五个区间也向左或向右挪就好

    • 主席树是真的虚,一定一定要多做点题,巩固老知识,才能更好学习新知识


    code

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXN 200005
    #define MAX 1000005
    #define ll long long
    #define fo(i,a,b) for (ll i=a;i<=b;++i)
    #define fd(i,a,b) for (ll i=a;i>=b;--i)
    
    using namespace std;
    
    ll lson[MAX*20],rson[MAX*20],sum[MAX*20];
    ll a[MAXN],root[MAXN];
    ll n,m,mx,k,p,tot;
    ll L[10],R[10];
    
    inline ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
    	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    inline void build(ll &t,ll l,ll r)
    {
    	t=++tot;
    	if (l==r)return;
    	ll mid=(l+r)>>1;
    	build(lson[t],l,mid),build(rson[t],mid+1,r);
    }
    inline void modify(ll old,ll &t,ll l,ll r,ll x)
    {
    	t=++tot;
    	lson[t]=lson[old],rson[t]=rson[old],sum[t]=sum[old];
    	if (l==r){++sum[t];return;}
    	ll mid=(l+r)>>1;
    	if (x<=mid)modify(lson[old],lson[t],l,mid,x);
    	else modify(rson[old],rson[t],mid+1,r,x);
    	sum[t]=sum[lson[t]]+sum[rson[t]];
    }
    inline ll query(ll l,ll r,ll x)
    {
    	if (l==r)return l;
    	ll mid=(l+r)>>1,tmp=0;
    	fo(i,1,k)tmp+=sum[lson[R[i]]]-sum[lson[L[i]]];
    	if (x<=tmp)
    	{
    		fo(i,1,k)L[i]=lson[L[i]],R[i]=lson[R[i]];
    		return query(l,mid,x);
    	}
    	else
    	{
    		fo(i,1,k)L[i]=rson[L[i]],R[i]=rson[R[i]];
    		return query(mid+1,r,x-tmp);
    	}
    }
    int main()
    {
    	freopen("T3.in","r",stdin);
    	n=read(),m=read();
    	fo(i,1,n)a[i]=read();
    	build(root[0],0,1000000);
    	fo(i,1,n)modify(root[i-1],root[i],0,1000000,a[i]);
    	while (m--)
    	{
    		k=read(),p=read();
    		fo(i,1,k)L[i]=root[read()-1],R[i]=root[read()];
    		printf("%lld
    ",query(0,1000000,p));
    	}
    	return 0;
    }
    
  • 相关阅读:
    c/c++字符串传递
    从一个小程序明白new和delete的奇特现象
    Linux下构造函数string需要注意的问题
    字符串转time_t
    CentOS7基础建站指南(笔记)
    图与搜索
    面向的对象编程的小猫腻
    多线程编程
    生产者消费者模式-Java实现
    Java-代理模式的理解
  • 原文地址:https://www.cnblogs.com/horizonwd/p/11165296.html
Copyright © 2011-2022 走看看