题目传送门

思路:树状数组套线段树模板题。

  什么是树状数组套线段树,普通的树状数组每个点都是一个权值,而这里的树状数组每个点都是一颗权值线段树,我们用前缀差分的方法求得每个区间的各种信息,

  其实关键就一句话,把树状数组更新的$sum[x]+=val$改成$Modify(rt[i],1,tot,a[pos],w);$。

  这道题的最大坑点就是分数可能重复,所以对于操作1和操作4要格外的小心,不能直接查,要通过查前面那个位置的数,然后加1得到当前位置(比如1,2,2,3。3的排名是3不是4,而一般的权值线段树,直接查询3可能会出来4)。

  然后就是抄板子抄代码了。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
#define fpn() freopen("simple.in","r",stdin)
#define rd read()
using namespace std;
typedef long long ll;
inline int read()
{
int x=,t=;char ch=getchar();
while((ch<''||ch>'')&&ch!='-')ch=getchar();
if(ch=='-')t=-,ch=getchar();
while(ch<=''&&ch>='')x=x*+ch-,ch=getchar();
return x*t;
}
const int maxn = ;
int op[maxn],l[maxn],rt[maxn],r[maxn],kk[maxn],a[maxn];
int ls[maxn*],rs[maxn*],sum[maxn*],cnt;
int n,m,s[maxn],tot,tp1[maxn],t1,tp2[maxn],t2;
int lowbit(int x){ return x & -x;};
void Modify(int &now,int l,int r,int p,int w){
if(!now)now=++cnt;
if(l==r){
sum[now]+=w;
return;
}
int mid=(l+r)>>;
if(p<=mid)Modify(ls[now],l,mid,p,w);
else Modify(rs[now],mid+,r,p,w);
sum[now]=sum[ls[now]]+sum[rs[now]];
}
void preModify(int pos,int w){
for(int i=pos;i<=n;i+=lowbit(i)){
Modify(rt[i],,tot,a[pos],w);
}
}
int query(int now,int l,int r,int k){
if(l==r)return sum[now];
int mid=(l+r)>>;
if(k<=mid)return query(ls[now],l,mid,k);
else return sum[ls[now]]+query(rs[now],mid+,r,k);
}
int Rank(int l,int r,int k){
int res=;
l--;
for(int i=r;i>;i-=lowbit(i)){
res+=query(rt[i],,tot,k);
}
for(int i=l;i>;i-=lowbit(i)){
res-=query(rt[i],,tot,k);
}
return res;
}
int kth(int l,int r,int k){
if(l==r)return l;
int su=,mid=(l+r)>>;
for(int i=;i<=t1;i++)su+=sum[ls[tp1[i]]];
for(int i=;i<=t2;i++)su-=sum[ls[tp2[i]]];
if(su>=k){
for(int i=;i<=t1;i++)tp1[i]=ls[tp1[i]];
for(int i=;i<=t2;i++)tp2[i]=ls[tp2[i]];
return kth(l,mid,k);
}else{
for(int i=;i<=t1;i++)tp1[i]=rs[tp1[i]];
for(int i=;i<=t2;i++)tp2[i]=rs[tp2[i]];
return kth(mid+,r,k-su);
}
}
int kthQuery(int l,int r,int k){
l--;
t1=t2=;
for(int i=r;i>;i-=lowbit(i)){
tp1[++t1]=rt[i];
}
for(int i=l;i>;i-=lowbit(i)){
tp2[++t2]=rt[i];
}
return s[kth(,tot,k)];
}
int main(){
//fpn();
n=rd,m=rd;
for(int i=;i<=n;i++){
a[i]=rd;
s[++tot]=a[i];
}
for(int i=;i<=m;i++)
{
op[i]=rd;
if(op[i]!=){
l[i]=rd,r[i]=rd,kk[i]=rd;
if(op[i]!=)s[++tot]=kk[i];
}else{
l[i]=rd,kk[i]=s[++tot]=rd;
}
}
sort(s+,s++tot);
tot=unique(s+,s++tot)-s-;
for(int i=;i<=n;i++)
{
a[i]=lower_bound(s+,s++tot,a[i])-s;
preModify(i,);
}
for(int i=;i<=m;i++)
{
if(op[i]==){
kk[i]=lower_bound(s+,s++tot,kk[i])-s;
printf("%d\n",Rank(l[i],r[i],kk[i]-)+);
}else if(op[i]==){
printf("%d\n",kthQuery(l[i],r[i],kk[i]));
}else if(op[i]==){
preModify(l[i],-);
a[l[i]]=lower_bound(s+,s++tot,kk[i])-s;
preModify(l[i],);
}else if(op[i]==){
kk[i]=lower_bound(s+,s++tot,kk[i])-s;
int gg=Rank(l[i],r[i],kk[i]-);
printf("%d\n",kthQuery(l[i],r[i],gg));
}else{
kk[i]=lower_bound(s+,s++tot,kk[i])-s;
int gg=Rank(l[i],r[i],kk[i]);
printf("%d\n",kthQuery(l[i],r[i],gg+));
}
}
return ;
}

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 6185  Solved: 2357
[Submit][Status][Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

最新文章

  1. jQuery中width、innerWidth、outerWidth的区别
  2. Html总结及日志目录
  3. 讲讲Handler+Looper+MessageQueue 关系
  4. C# 表达式学习积累
  5. 基于APK的Robotium登录人人网与发状态
  6. Meta标签中的format-detection属性及含义
  7. border做箭头的例子
  8. 【android】优秀的UI资源站点集合
  9. js 条件判断放大字体
  10. Swift\本地文件管理
  11. Stem Cell 华人科学家
  12. IOS UIScrollView常用代理方法
  13. AES加密解密——AES在JavaWeb项目中前台JS加密,后台Java解密的使用
  14. python_如何为元组中每个元素命名
  15. 自制stm32板子无法烧录程序的问题
  16. css 冷知识
  17. pycharm 新建文件自动添加表头信息
  18. 利用PHP连接数据库——实现用户登录注册功能以及管理员对用户注册的审核功能
  19. 【转载】解决gridview空行时不显示的问题
  20. maven docker 插件集成的几个小坑

热门文章

  1. Java c3p0 连接 MySQL
  2. 17-pow(c++)
  3. Mock Server实践
  4. Hyperledger Fabric Orderer节点启动
  5. Oracle——创建和管理表
  6. 20169219 TCP_IP网络协议攻击实验报告
  7. c# 半角转换为全角 判断是否是全角
  8. EBS取Web字段SQL操作文档
  9. Backbone.js 0.9.2 中文解释
  10. 吐槽一下wp toolkit ToggleSwitch控件