BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果
Sample Input
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
2
1
HINT
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
题解:
题意概括
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
题解
让我们来考虑神奇的分治算法。
整体二分!!(当你会了)
首先当你已经掌握了树状数组的区间加和区间询问(如果不会->点这里)
我们考虑二分答案。
注意进行以下操作要严格按照输入时间先后顺序来。
首先对于加进去的数字c,我们把他变成n-c+1,这样就把询问前k大变成了前k小。
如果是修改操作,如果修改的值比当前的mid值小,就修改,并扔到左区间里面。否则扔到右边。
如果是询问操作,如果在当前的状态下,该询问的区间内查询到的数的个数res比当前询问的c要大(或者相等),那么显然答案在左区间,把他扔到左边,否则把他的c减掉res再扔到右边去。
然后递归分治两个区间就可以了。
(本质是个二分答案的升级版)
参考代码:
/**************************************************************
Problem: 3110
User: SongHL
Language: C++
Result: Accepted
Time:1880 ms
Memory:3640 kb
****************************************************************/ #include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&-x
#define clr(a,b) memset(a,b,sizeof a)
typedef long long ll;
const int maxn=;
int n,m,id[maxn],templ[maxn],tempr[maxn];
ll tree[][maxn];
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while(ch>=''&&ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
inline void add(int t,int x,int y)//单点加
{
while(x<=n+)
{
tree[t][x]+=y;
x+=lowbit(x);
}
}
inline void update(int l,int r,int val)//区间加
{
add(,l,val);add(,l,l*val);
add(,r+,-val);add(,r+,-val*(r+));
}
inline ll Sum(int t,int x)//前缀和
{
ll ans=;
while(x>)
{
ans+=tree[t][x];
x-=lowbit(x);
}
return ans;
}
inline ll query(int l,int r)//区间求和
{
return Sum(,r)*(r+)-Sum(,l)*l-Sum(,r)+Sum(,l);
}
struct Node{
int type,l,r,x,ans;
void Get()
{
type=read();l=read();r=read();x=read();
if(type==) x=n-x+;
}
} a[maxn]; inline void Solve(int lx,int rx,int l,int r)
{
if(l>r) return ;
if(lx==rx)
{
for(int i=l;i<=r;++i) a[id[i]].ans=lx;
return ;
}
int midx=lx+rx>>;
int L=,R=;
for(int i=l;i<=r;++i)
{
if(a[id[i]].type==)
{
if(a[id[i]].x<=midx) templ[++L]=id[i],update(a[id[i]].l,a[id[i]].r,);
else tempr[++R]=id[i];
}
else
{
ll res=query(a[id[i]].l,a[id[i]].r);
if(res>=a[id[i]].x) templ[++L]=id[i];
else tempr[++R]=id[i],a[id[i]].x-=res;
}
}
for(int i=;i<=L;++i)
{
if(a[templ[i]].type==)
update(a[templ[i]].l,a[templ[i]].r,-);
} for(int i=l;i<=l+L-;++i) id[i]=templ[i-(l-)];
for(int i=r-R+;i<=r;++i) id[i]=tempr[i-(r-R)]; Solve(lx,midx,l,l+L-);
Solve(midx+,rx,r-R+,r);
} int main()
{
n=read();m=read();
for(int i=;i<=m;++i) a[i].Get(),id[i]=i;
clr(tree,);
Solve(,*n+,,m);
for(int i=;i<=m;++i)
if(a[i].type==) printf("%d\n",n-a[i].ans+);
return ;
}
BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)的更多相关文章
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )
BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...
- [BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- Cogs 1345. [ZJOI2013] K大数查询(树套树)
[ZJOI2013] K大数查询 /* 树套树写法. bzoj过不了. 可能有负数要离散吧. 线段树套线段树. 外层权值线段树,内层区间线段树维护标记. 对权值建一棵权值线段树. 某个点表示权值在某个 ...
- 【BZOJ3110】[Zjoi2013]K大数查询 树套树
[BZOJ3110][Zjoi2013]K大数查询 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c,如果 ...
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- [BZOJ3110][ZJOI2013]K大数查询(整体二分)
BZOJ Luogu sol 整体二分,其实很简单的啦. 对所有询问二分一个答案mid,把所有修改操作中数字大于mid的做一个区间覆盖(区间加1) 查询就是区间查询 然后左右分一分即可 注意是第k大 ...
随机推荐
- python函数的基本语法<二>
函数的流程控制: if...else... a = 100 b = 200 if a == 100 and b ==300: print('100,200') elif b == 200: print ...
- Centos 7环境下修改主机名
步骤如下: 一.首先把虚拟机打开,用root账户进行登录后打开终端 二.我们看到我们虚拟机名称是默认的主机名. 三.用vi编辑器编辑etc目录下的hostname文件,输入“vi /etc/hostn ...
- Secure CRT注册码
secure CRT 把记忆的东西放在这就行了,:) SecureCRT 5.2.2的注册码 Name: Apollo InteractiveCompany: Apollo ...
- nyoj 58-最少步数 (BFS)
58-最少步数 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:17 submit:22 题目描述: 这有一个迷宫,有0~8行和0~8列: 1,1,1 ...
- Java开发者入职必备条件
01.基础技术体系 我认为知识技能体系化是判断技术是否过关的第一步.知识体系化包含两层含义: 1. 能够知道技术知识图谱(高清版图谱扫文末二维码)的内容 比如分布式系统中常用的RPC技术,其背后就涉及 ...
- ef+Npoi导出百万行excel之踩坑记
最近在做一个需求是导出较大的excel,本文是记录我在做需求过程中遇到的几个问题和解题方法,给大家分享一下,一来可以帮助同样遇到问题的朋友,二呢,各位大神也许有更好的方法可以指点小弟一 ...
- 学习记录:《C++设计模式——李建忠主讲》2.面向对象设计原则
1.课程内容: 重新认识面向对象:面向对象设计原则: 2.重新认识面向对象 1)理解隔离变化:从宏观层面来看,面向对象的构建方式更能适应软件的变化,将变化所带来的影响减为最小: 2)各司其职:从微观层 ...
- bind cname
$TTL 1D @ IN SOA @ rname.invalid. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS ...
- Hadoop之HDFS文件系统
概念 HDFS,它是一个文件系统,用于存储文件,通过目录树来定位文件:其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色. HDFS的设计适合一次写入,多次读出的场景,且不 ...
- 2019-10-30,Hack The Box 获取邀请码
一.快速获取邀请码方法 1,使用curl请求下面的地址curl -X POST https://www.hackthebox.eu/api/invite/generate 2,在返回结果的code部分 ...