• [hdu-6621]K-th Closest Distance 主席树 线段树 2019 多校4


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6621

    题意:给一个数组,多次询问 l,r,k,p,问 l~r区间 第k小的|p-ai|是多少
    1<=p、ai<1e6 、1 <= K <= 169, R - L + 1 >= K,1 <= n, m <= 10^5

    题解:二分答案+主席树
    二分绝对值答案r,然后用主席树查[p-r , p+r]区间有多少个数,如果大于等于k个减小r并记录答案,小于k个增大r
    有一种情况是r满足k个,但是这个r的答案不存在,这时候会二分更小的r,直到精确到存在的那个r
    主席树维护 当前节点l~r值范围内的数总个数有几个

    官方题解

    Using segment tree, we can find the number of values smaller than p in [L, R] within O(log(n)).

    So by using binary search method, we can find the answer in O(log(n)^2) time.

    Total time complexity is O(N log(N) + Q log(N)^2).

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int const maxn=1e5+100,maxn2=1e6+10;
     5 int m,n,q,a[maxn],tot,froot[maxn],c[maxn2*30],lson[maxn2*30],rson[maxn2*30];//主席树的空间开n的40倍一般够了
     6 
     7 int update(int root,int pos,int val){//加入一个新的值后新的树,root是前一棵树
     8     int newroot=tot++,tmp=newroot;
     9     c[newroot]=c[root]+val;//新树的结点值=原先树的值+新加的
    10     int l=1,r=1e6;
    11     while(l<r){
    12         int mid=(l+r)>>1;
    13         if(pos<=mid){//看修改的值位于哪颗子树上
    14             lson[newroot]=tot++;rson[newroot]=rson[root];//如果位于左子树上,则右子树的值可以利用原先的树
    15             newroot = lson[newroot];root=lson[root];
    16             r=mid;
    17         }
    18         else {
    19             rson[newroot]=tot++;lson[newroot]=lson[root];
    20             newroot=rson[newroot];root=rson[root];
    21             l=mid+1;
    22         }
    23         c[newroot]=c[root]+val;
    24     }
    25     return tmp;//新的树的根节点
    26 }
    27 int query(int l,int r,int k,int lr,int rr){
    28     //当前点l、r时刻树编号编号分别为lr、rr,
    29     //当前点控制区间为[l,r],要查询区间为[1,k] 
    30     if(k>=r)return c[rr]-c[lr];
    31     int mid=(l+r)>>1,ans=0;
    32     if(1<=mid)ans+=query(l,mid,k,lson[lr],lson[rr]);
    33     if(k>mid)ans+=query(mid+1,r,k,rson[lr],rson[rr]);
    34     return ans;
    35 }
    36 int query_node(int lr,int rr,int p,int k){//用线段树维护个数
    37     int l=0,r=1e6,mid,ans,al,ar,gg;//二分绝对值答案的半径    |p-ai|
    38     while(l<=r){
    39         mid=(l+r)>>1;        
    40         al=p-mid,ar=p+mid;//看al——ar区间有多少个数,若<k个,则半径要增大,若<=k个,半径可能对,可能需要减小(因为当前分到的数可能不存在),但答案一定是稍微大了可以小了不行。
    41         if(al<=1)gg=query(1,1e6,ar,froot[lr],froot[rr]);//若al<0,就看0~ar有多少个数
    42         else gg=query(1,1e6,ar,froot[lr],froot[rr])-query(1,1e6,al-1,froot[lr],froot[rr]);
    43         if(gg>=k){
    44             ans=mid;r=mid-1;
    45         }
    46         else l=mid+1;
    47     }
    48     return ans;
    49 }
    50 int build(int l,int r){//初始建树
    51     int root=tot++;
    52     c[root]=0;
    53     if(l!=r){
    54         int mid=(l+r)>>1;
    55         lson[root]=build(l,mid);
    56         rson[root]=build(mid+1,r);
    57     }
    58     return root;
    59 }
    60 inline int get_num(){
    61     char ch;
    62     bool flag=false;
    63     int num=0;
    64     ch=getchar();
    65     while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
    66     while(ch>='0'&&ch<='9'){num=(num<<3)+(num<<1)+ch-'0';ch=getchar();}
    67     if(flag)return -1*num;
    68     return num;
    69 }
    70 int main(){
    71         int T,ans;
    72         scanf("%d",&T);
    73         while(T--){
    74         scanf("%d%d",&n,&q);
    75         tot=0,ans=0;
    76         for(int i=1;i<=n;i++){
    77             a[i]=get_num();
    78         }
    79         
    80         froot[0]= build(1,1e6);
    81         for(int i=1;i<=n;i++){
    82             froot[i]=update(froot[i-1],a[i],1);
    83         }
    84         while(q--){
    85             int l,r,p,k;
    86             l=get_num()^ans,r=get_num()^ans,p=get_num()^ans,k=get_num()^ans;
    87             ans=query_node(l-1,r,p,k);
    88             printf("%d
    ",ans);
    89         }    
    90         }
    91         
    92     return 0;
    93 }
  • 相关阅读:
    between and 相关
    SQL获取所有用户名,数据库名、所有表名、所有字段名及字段类型
    性能优化探讨与分析:
    设置自动收缩数据库
    服务器注册
    多表查询及区别
    sql孤立用户解决方法
    委托、事件、观察者模式
    非托管资源
    C# 预处理器指令
  • 原文地址:https://www.cnblogs.com/conver/p/11286918.html
Copyright © 2020-2023  润新知