[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 }

原文地址:https://www.cnblogs.com/conver/p/11286918.html

时间: 2024-10-09 18:50:56

[hdu-6621]K-th Closest Distance 主席树 线段树 2019 多校4的相关文章

HDU - 6621 K-th Closest Distance 主席树+二分答案

K-th Closest Distance 主席树第二波~ 题意 给你\(n\)个数\(m\)个询问,问\(i\in [l,r]\)计算每一个\(|a_{i}-p|\)求出第\(k\)小 题目要求强制在线\(l = l \oplus ans.r = r \oplus ans.p = p \oplus ans.k = k \oplus ans\)(ans为上次询问的答案) 思路 二分答案\(ans\),找区间\(i\in[l,r], a_{i} \in [p-ans, p+ans]\)里的数量\(

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

hdu 4970 killing monster 代代相传刷qq 不用线段树啦~

[题意]塔防游戏,一条n长的路上,有m个炮台,可以覆盖[li,ri]范围,威力ci,即每一秒,炮塔可以对范围 内的怪物可以造成ci点伤害.只有有q只怪物,每只怪物有hi点血,出现位置为xi:当怪物血量减少到0或以下时消失,怪物一直朝n位置前进.问有几只怪物可以离开这条路. [题解]用线段树可以做,不过还好我们有代代相传的刷qq 算法 ,让解法变得简单的多~    ^_^ 1 #include <iostream> 2 #include <cstdio> 3 #include <

hdu 5023 A Corrupt Mayor&#39;s Performance Art(线段树区间更新)

#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; int tree[5001000],add[5001000]; int color[50]; int n,m; void pushup(int pos) { tree[pos]=tree[pos<<1]|tree[pos<<1|1]; //更新

hdu 5023 A Corrupt Mayor&#39;s Performance Art (线段树+区间更新+状压)

A Corrupt Mayor's Performance Art Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submission(s): 699    Accepted Submission(s): 267 Problem Description Corrupt governors always find ways to get dirty money.

hdu 1754  I Hate It (线段树)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 35640    Accepted Submission(s): 14034 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的

hdu 1823 Luck and Love ,二维线段树

Luck and Love Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5282    Accepted Submission(s): 1324 Input 本题有多个测试数据,第一个数字M,表示接下来有连续的M个操作,当M=0时处理中止. 接下来是一个操作符C. 当操作符为'I'时,表示有一个MM报名,后面接着一个整数,H表示身

Codeforces 458C Elections 贿赂选票抢主席! 线段树

题目链接:点击打开链接 题意: 给定n张选票,每张选票有2个参数,第一个参数表示这张选票选的人 第二个参数表示如果让这张选票改为选0号 的花费 问:使得0号的选票是最高的(不能有和0号相同)的最小花费 枚举0号的最终选票 那么已知0号最终选票,则有些人选票比0号大的,那些票都要买下来. 如果买完了还是达不到 最终选票,就从所有剩下的选票里找前k小的. 用线段树求前k小的数的和,然后_(:зゝ∠)_就可以了 #include<iostream> #include<cstdio> #i

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp