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

Posted conver

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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\n",ans);
89             
90         
91         
92     return 0;
93 

 

以上是关于[hdu-6621]K-th Closest Distance 主席树 线段树 2019 多校4的主要内容,如果未能解决你的问题,请参考以下文章

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

2019杭电多校赛第四场 HDU6621 K-th Closest Distance 主席树 二分

2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

K-th Closest Distance

K-th Closest Distance