用主席树写起来跑的快一点,而且也很傻比,二分答案,即二分那个半径就行

主席树求的是区间<=k的个数

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
int a[maxn],n,m; struct Node{int lc,rc,v;}t[maxn*];
int rt[maxn],tot;
int update(int last,int l,int r,int pos){
int now=++tot;
t[now]=t[last];
t[now].v++;
if(l==r)return now;
int m=l+r>>;
if(pos<=m)
t[now].lc=update(t[last].lc,l,m,pos);
else t[now].rc=update(t[last].rc,m+,r,pos);
return now;
}
int query(int st,int ed,int L,int R,int l,int r){
if(L>R)return ;
if(L<=l && R>=r)return t[ed].v-t[st].v;
int m=l+r>>,res=;
if(L<=m)res+=query(t[st].lc,t[ed].lc,L,R,l,m);
if(R>m)res+=query(t[st].rc,t[ed].rc,L,R,m+,r);
return res;
}
int build(int l,int r){
int now=++tot;
t[now].lc=t[now].rc=t[now].v=;
if(l==r)return now;
int m=l+r>>;
t[now].lc=build(l,m);
t[now].rc=build(m+,r);
return now;
}
void init(){
memset(rt,,sizeof rt);
memset(t,,sizeof t);
tot=;
} int main(){
int t;cin>>t;
while(t--){
init();
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
rt[]=build(,n);
for(int i=;i<=n;i++)
rt[i]=update(rt[i-],,,a[i]); int ans=,l,r,p,k;
while(m--){
scanf("%d%d%d%d",&l,&r,&p,&k);
l^=ans,r^=ans,p^=ans,k^=ans; int L=,R=,mid;ans=;
while(L<=R){
mid=L+R>>;
int res1=query(rt[l-],rt[r],,mid+p,,);
int res2=query(rt[l-],rt[r],,p-mid-,,);
if(res1-res2>=k)
ans=mid,R=mid-;
else L=mid+;
}
cout<<ans<<'\n';
}
}
}

线段树的话就要模拟一下归并排序的过程,即线段树结点维护的是区间的有序序列

然后还是二分答案,然后查询的是区间[l,r]范围内在[p-mid,p+mid]范围内的数个数,要特别注意查询的方式

     int res1=lower_bound(seg[rt].begin(),seg[rt].end(),v1)-seg[rt].begin();
int res2=upper_bound(seg[rt].begin(),seg[rt].end(),v2)-seg[rt].begin();//上界一定要用upper_bound!
return res2-res1;
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define maxn 100005
int n,k,l,r,ans,p,m,a[maxn]; #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
vector<int>seg[maxn<<];
void pushup(int rt){
int s=seg[rt<<].size(),t=seg[rt<<|].size(),i=,j=;
while(i!=s && j!=t){
if(seg[rt<<][i]<=seg[rt<<|][j])
seg[rt].push_back(seg[rt<<][i]),i++;
else seg[rt].push_back(seg[rt<<|][j]),j++;
}
while(i!=s){
seg[rt].push_back(seg[rt<<][i]);
i++;
}
while(j!=t){
seg[rt].push_back(seg[rt<<|][j]);
j++;
}
} void build(int l,int r,int rt){
seg[rt].clear();
if(l==r){
seg[rt].push_back(a[l]);return;
}
int m=l+r>>;
build(lson);build(rson);
pushup(rt);
}
int query(int L,int R,int v1,int v2,int l,int r,int rt){
if(L<=l && R>=r){
int res1=lower_bound(seg[rt].begin(),seg[rt].end(),v1)-seg[rt].begin();
int res2=upper_bound(seg[rt].begin(),seg[rt].end(),v2)-seg[rt].begin();
return res2-res1;
}
int m=l+r>>,res=;
if(L<=m)res+=query(L,R,v1,v2,lson);
if(R>m)res+=query(L,R,v1,v2,rson);
return res;
} int judge(int mid){
int res=;//查找半径是mid
res=query(l,r,p,p+mid,,n,);
if(res>=k)return ;
res+=query(l,r,p-mid,p-,,n,);
if(res>=k)return ;
return ;
} int main(){
int t;cin>>t;
while(t--){
n=k=l=r=ans=p=m=; scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
build(,n,); while(m--){
scanf("%d%d%d%d",&l,&r,&p,&k);
l^=ans,r^=ans,p^=ans,k^=ans;
int L=,R=,mid;
ans=;
while(L<=R){//二分半径
mid=L+R>>;
if(judge(mid))
ans=mid,R=mid-;
else L=mid+;
}
cout<<ans<<'\n';
}
}
}

主席树/线段树模拟归并排序+二分答案(好题)——hdu多校第4场08的更多相关文章

  1. cogs 2109. [NOIP 2015] 运输计划 提高组Day2T3 树链剖分求LCA 二分答案 差分

    2109. [NOIP 2015] 运输计划 ★★★☆   输入文件:transport.in   输出文件:transport.out   简单对比时间限制:3 s   内存限制:256 MB [题 ...

  2. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  3. HDU 5649 DZY Loves Sorting(二分答案+线段树/线段树合并+线段树分割)

    题意 一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位. \(1 \leq n \le ...

  4. [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)

    解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...

  5. [CSP-S模拟测试]:树(树上上升序列+主席树+线段树)

    题目传送门(内部题78) 输入格式 第一行输入两个整数$n,q$,表示节点数和询问数. 第二行输入$n$个整数$w_i$,表示第$i$个点的智商. 第三行至第$n+1$行每行输入两个数$x,y$,表示 ...

  6. BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...

  7. EC Round 33 F. Subtree Minimum Query 主席树/线段树合并

    这题非常好!!! 主席树版本 很简单的题目,给一个按照指定节点的树,树上有点权,你需要回答给定节点的子树中,和其距离不超过k的节点中,权值最小的. 肯定首先一想,按照dfs序列建树,然后按照深度为下标 ...

  8. POJ2104 K-th Number 不带修改的主席树 线段树

    http://poj.org/problem?id=2104 给定一个序列,求区间第k小 通过构建可持久化的点,得到线段树左儿子和右儿子的前缀和(前缀是这个序列从左到右意义上的),然后是一个二分的ge ...

  9. Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6471  Solved: 2697[Su ...

随机推荐

  1. C++中的delete加深认识

    delete操作: 我们在删除一个指针之后,编译器只会释放该指针所指向的内存空间,而不会删除这个指针本身. 1.假如你不去释放,那么该区域的内存始终不能被其他数据所使用.2.指向该内存的指针是个局部变 ...

  2. C++32位和64位常见类型的大小

             32位      64位 char      1       1 int                       4      大多数4,少数8 long      4      ...

  3. Oracle实现主键自增的几种方式

    数据库作为一个系统的核心,数据库设计的1NF就是一个表结构必须有唯一约束也就是主键,Oracle数据库本身没有自增机制,不像MySQL直接使用关键字AUTO_INCREMENT自动加一,所以需要我们去 ...

  4. informix 计算 日期之差

    原文地址:http://blog.chinaunix.net/uid-678894-id-3138829.html https://blog.csdn.net/zhengqiqiqinqin/arti ...

  5. Ubuntu 图形桌面死机重启(机器不重启)

    Ubuntu的图形界面容易死机,如果正在跑程序的话又不能重启.这时候可以通过终端来_重启_图形界面. 首先按Alt+Ctrl+F1进入终端界面.查看图形界面的进程: ps -t tty7 查看到名为X ...

  6. sql 数据库

    在关系数据库中,最常用的操作就是查询.直线电机推杆 准备数据 为了便于讲解和练习,我们先准备好了一个students表和一个classes表,它们的结构和数据如下: students表存储了学生信息: ...

  7. Android_开发片段(Part 2)

    1.List和Map知识: 1)如何定义 List<Map<String,Object>> list=new ArrayList<Map<String,Object ...

  8. (转)OpenFire源码学习之二十七:Smack源码解析

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...

  9. legend2---开发日志16

    legend2---开发日志16 一.总结 一句话总结: 编程敲代码,一定要把 关系弄清楚,关系不弄清楚,很容易敲错,比如:如何求无限级分类的博客的数据的数目 弄清楚关系式:自己总数量=孩子总数量+自 ...

  10. 关闭windows的DEP

    1.与开启dep时一样,按组合键win+r打开运行窗口,输入cmd并按回车,如图所示:    2.调出命令提示符窗口后,输入bcdedit.exe/set {current} nx AlwaysOff ...