BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ3110
题意概括
有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
UPD(2018-04-01):之前抄的树套树是真的丑到爆。今天用分治做了一遍QAQ。
题解
让我们来考虑神奇的分治算法。
整体二分!!(当你会了)
首先当你已经掌握了树状数组的区间加和区间询问(如果不会->点这里)
我们考虑二分答案。
注意进行以下操作要严格按照输入时间先后顺序来。
首先对于加进去的数字c,我们把他变成n-c+1,这样就把询问前k大变成了前k小。
如果是修改操作,如果修改的值比当前的mid值小,就修改,并扔到左区间里面。否则扔到右边。
如果是询问操作,如果在当前的状态下,该询问的区间内查询到的数的个数res比当前询问的c要大(或者相等),那么显然答案在左区间,把他扔到左边,否则把他的c减掉res再扔到右边去。
然后递归分治两个区间就可以了。
(本质是个二分答案的升级版)
然而博主非常非常非常非常非常非常的菜。千辛万苦调出样例,交一发WA。找了半天发现树状数组打萎掉了。
然后推式子不下于3遍。校对lych大佬的代码不下于5遍,还是没发现错误。
woc心态爆炸bonebonebone!
还是没发现错误。
发现了。最难发现的地方。tree[2][N]打成了tree[N][2]……QAQ
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=50005;
int n,m,id[N],tmpL[N],tmpR[N];
LL tree[2][N];
int lowbit(int x){
return x&-x;
}
void add(int t,int x,int y){
for (;x<=n+1;x+=lowbit(x))
tree[t][x]+=y;
}
void update(int L,int R,int v){
add(0,L,v),add(1,L,v*L);
add(0,R+1,-v),add(1,R+1,-v*(R+1));
}
LL sum(int t,int x){
LL ans=0;
for (;x>0;x-=lowbit(x))
ans+=tree[t][x];
return ans;
}
LL query(int L,int R){
return sum(0,R)*(R+1)-sum(0,L)*L-sum(1,R)+sum(1,L);
}
struct opts{
int type,a,b,c,ans;
void get(){
scanf("%d%d%d%d",&type,&a,&b,&c);
if (type==1)
c=n-c+1;
}
}a[N];
void solve(int xL,int xR,int L,int R){
if (L>R)
return;
if (xL==xR){
for (int i=L;i<=R;i++)
a[id[i]].ans=xL;
return;
}
int xmid=(xL+xR)>>1;
int l=0,r=0;
for (int i=L;i<=R;i++)
if (a[id[i]].type==1){
if (a[id[i]].c<=xmid)
tmpL[++l]=id[i],update(a[id[i]].a,a[id[i]].b,1);
else
tmpR[++r]=id[i];
}
else {
LL res=query(a[id[i]].a,a[id[i]].b);
if (res>=a[id[i]].c)
tmpL[++l]=id[i];
else
tmpR[++r]=id[i],a[id[i]].c-=res;
}
for (int i=1;i<=l;i++)
if (a[tmpL[i]].type==1)
update(a[tmpL[i]].a,a[tmpL[i]].b,-1);
for (int i=L;i<=L+l-1;i++)
id[i]=tmpL[i-(L-1)];
for (int i=R-r+1;i<=R;i++)
id[i]=tmpR[i-(R-r)];
solve(xL,xmid,L,L+l-1);
solve(xmid+1,xR,R-r+1,R);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
a[i].get(),id[i]=i;
memset(tree,0,sizeof tree);
solve(1,2*n+1,1,m);
for (int i=1;i<=m;i++)
if (a[i].type==2)
printf("%d\n",n-a[i].ans+1);
return 0;
}
———————old———————(2017-12-19)
题解
树套树裸题。
外层套权值线段树,内层套区间线段树。
标记永久化比较好写。
空间随便卡卡就过去了。
代码
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=50005,NN=N*2,K=220;
struct Position_Segment_Tree{
int tot,ls[N*K],rs[N*K];
LL add[N*K],sum[N*K];
void clear(){
tot=0;
memset(ls,0,sizeof ls);
memset(rs,0,sizeof rs);
memset(add,0,sizeof add);
memset(sum,0,sizeof sum);
}
void update(int &rt,int le,int ri,int xle,int xri){
if (!rt)
rt=++tot;
if (xle<=le&&ri<=xri){
add[rt]++;
return;
}
sum[rt]+=xri-xle+1;
int mid=(le+ri)>>1;
if (xri<=mid)
update(ls[rt],le,mid,xle,xri);
else if (xle>mid)
update(rs[rt],mid+1,ri,xle,xri);
else {
update(ls[rt],le,mid,xle,mid);
update(rs[rt],mid+1,ri,mid+1,xri);
}
}
LL query(int rt,int le,int ri,int xle,int xri){
if (!rt)
return 0;
if (xle<=le&&ri<=xri)
return sum[rt]+add[rt]*(xri-xle+1);
int mid=(le+ri)>>1;
LL res=add[rt]*(xri-xle+1);
if (xri<=mid)
return res+query(ls[rt],le,mid,xle,xri);
else if (xle>mid)
return res+query(rs[rt],mid+1,ri,xle,xri);
else
return res+query(ls[rt],le,mid,xle,mid)
+query(rs[rt],mid+1,ri,mid+1,xri);
}
}PST;
int n,nn,m;
int tr[NN*4];
void update(int rt,int le,int ri,int pos,int xle,int xri){
PST.update(tr[rt],1,n,xle,xri);
if (le==ri)
return;
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
if (pos<=mid)
update(ls,le,mid,pos,xle,xri);
else
update(rs,mid+1,ri,pos,xle,xri);
}
int query(int rt,int le,int ri,int xle,int xri,LL k){
if (le==ri)
return le;
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
LL Rz=PST.query(tr[rs],1,n,xle,xri);
if (k<=Rz)
return query(rs,mid+1,ri,xle,xri,k);
else
return query(ls,le,mid,xle,xri,k-Rz);
}
int main(){
scanf("%d%d",&n,&m);
nn=n*2+1;
PST.clear();
while (m--){
int op,a,b,c;
scanf("%d%d%d%d",&op,&a,&b,&c);
if (op==1)
update(1,1,nn,c+n+1,a,b);
else
printf("%d\n",query(1,1,nn,a,b,c)-n-1);
}
return 0;
}
BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组的更多相关文章
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】
模板题,折腾了许久. cqd分治整体二分,感觉像是把询问分到答案上. #include <bits/stdc++.h> #define rep(i, a, b) for (int i = ...
- [BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- [BZOJ3110][ZJOI2013]K大数查询(整体二分)
BZOJ Luogu sol 整体二分,其实很简单的啦. 对所有询问二分一个答案mid,把所有修改操作中数字大于mid的做一个区间覆盖(区间加1) 查询就是区间查询 然后左右分一分即可 注意是第k大 ...
随机推荐
- rsyslog的安装、使用、详解
操作系统:CentOS release 6.7 download yum repo file:rsyslogall.repo [rsyslog-v8-stable] name=Adiscon Rsys ...
- VMware虚拟机安装Linux系统centos7(一)
1.安装虚拟机(自行百度) 2.编辑虚拟机设置 光驱设置,镜像选择:(也可设置2核2G,基于自己计算机选择!) 3.点击开启此虚拟机(上下键选择安装,回车) 4.选择语言 5.设置 如果想安装图形化界 ...
- Modbus库开发笔记之九:利用协议栈开发Modbus TCP Server应用
前面我们已经完成了Modbus协议栈的开发,但这不是我们的目的.我们开发它的目的当然是要使用它来解决我们的实际问题.接下来我们就使用刚开发的Modbus协议栈开发一个Modbus TCP Server ...
- 关于vue的基础概念
vue-cli相当于脚手架 给你自动生成模板工程vue-router是 vue路由插件 支持你单页应用的vue-loader是webpack下loader插件 可以把.vue文件 输出成组件
- django模板导入外部js和css等文件
1.新建文件夹templates(存放模板文件),新建文件夹media(存放js.css.images文件夹),并把两个文件夹放到了项目的根目录下 2.设定模板路径 设置模板路径比较简单,只要在set ...
- 简化版的AXI-LITE4和配合使用的RTL
////////////////////////////////////////////////////////////////////////////////// // // The ZYNQ FI ...
- string标准C++中的的用法总结(转)
转自:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html 相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻 ...
- 《剑指offer》顺时针打印矩阵
本题来自<剑指offer> 顺时针打印矩阵 题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 1 ...
- 实习笔记 burpsuite
1.通过设置拦截HTTPS协议消息: 拦截HTTPS协议消息,HTTPS在原有的基础上增加了安全套接字层SSL协议,通过CA证书来验证服务器的身份,在拦截设置中,绑定端口有三种模式,分别是仅本地回路模 ...
- bzoj 3529
非常好的一道莫比乌斯反演题,对提升自己的能力有很大帮助. 首先我们分析一下题意:题意让我们求,其中 那么我们首先对后面的式子进行一下变形,变形过程详见https://blog.csdn.net/lle ...