[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 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)