数据结构(树套树):ZJOI 2013 K大数查询
有几个点卡常数……
发现若第一维为位置,第二维为大小,那么修改时第一维修改区间,查询时第一维查询区间,必须挂标记。而这种情况下标记很抽象,而且Push_down不是O(1)的,并不可行。
那要怎么做呢?不妨交换一下,第一维为大小,第二维为位置,在第二维中挂标记,这样Push_down就是O(1)的了。
做完这道题,我最大的启发就是:树套树不适于在第一维挂标记,因为标记的维度会是一维的,根本不好维护。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <ctime>
using namespace std;
const int maxn=;
const int maxm=;
int rt[maxn*],tot,n,m;
int ch[maxm][],sum[maxm],tag[maxm]; void Push_up(int x){
sum[x]=sum[ch[x][]]+sum[ch[x][]];
} void Add(int &x,int l,int r,int d){
if(!x)x=++tot;
sum[x]+=(r-l+)*d;
tag[x]+=d;
} void Push_down(int x,int l,int r){
if(tag[x]&&l!=r){
int mid=(l+r)>>;
if(!ch[x][])ch[x][]=++tot;
if(!ch[x][])ch[x][]=++tot;
sum[ch[x][]]+=(mid-l+)*tag[x];tag[ch[x][]]+=tag[x];
sum[ch[x][]]+=(r-mid)*tag[x];tag[ch[x][]]+=tag[x];
tag[x]=;
}
} void Update(int &x,int l,int r,int a,int b){
if(!x)x=++tot;
Push_down(x,l,r);
if(l>=a&&r<=b){sum[x]+=r-l+;tag[x]+=;return;}
int mid=(l+r)>>;
if(mid>=a)Update(ch[x][],l,mid,a,b);
if(mid<b)Update(ch[x][],mid+,r,a,b);
Push_up(x);
} void Modify(int x,int l,int r,int g,int a,int b){
Update(rt[x],,n,a,b);
if(l==r)return;
int mid=(l+r)>>;
if(mid>=g)Modify(x<<,l,mid,g,a,b);
else Modify(x<<|,mid+,r,g,a,b);
} int Query(int x,int l,int r,int a,int b){
if(!x)return ;
Push_down(x,l,r);
if(l>=a&&r<=b)return sum[x];
int mid=(l+r)>>,ret=;
if(mid>=a)ret=Query(ch[x][],l,mid,a,b);
if(mid<b)ret+=Query(ch[x][],mid+,r,a,b);
return ret;
} int Solve(int l,int r,int k){
int lo=,hi=n,p=;
while(lo<hi){
int mid=(lo+hi)>>,tmp;
tmp=Query(rt[p<<],,n,l,r);
if(tmp>=k)hi=mid,p<<=;
else lo=mid+,p=p<<|,k-=tmp;
}
return hi;
} int op,a,b,c;
int main(){
#ifndef ONLINE_JUDGE
freopen("zjoi13_sequence.in","r",stdin);
freopen("zjoi13_sequence.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d%d%d",&op,&a,&b,&c);
if(op==)Modify(,,n,n-c+,a,b);
else printf("%d\n",n-Solve(a,b,c)+);
}
//printf("%.2f\n",(double)clock()/CLOCKS_PER_SEC);
return ;
}
然后就是喜闻乐见的整体二分,很好理解。
有些地方没有缩行,打丑了,理论上60行足矣,这就是整体二分的威力!
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=;
struct Node{
int tp,l,r,k,id,tmp;
}p[maxn],tmp[maxn]; int b0[maxn],b1[maxn];
int v0[maxn],v1[maxn];
int ans[maxn],n,Q,tim,cntQ; void Add0(int x,int d){
while(x<=n){
b0[x]=v0[x]==tim?b0[x]+d:d;
v0[x]=tim;
x+=x&(-x);
}
} void Add1(int x,int d){
while(x<=n){
b1[x]=v1[x]==tim?b1[x]+d:d;
v1[x]=tim;
x+=x&(-x);
}
} void Update(int l,int r,int d){
Add0(l,d);
Add0(r+,-d);
Add1(l,-(l-)*d);
Add1(r+,r*d);
} int Query(int x){
int ret=;
for(int i=x;i;i-=i&(-i))
ret+=v0[i]==tim?b0[i]:;
ret*=x;
for(int i=x;i;i-=i&(-i))
ret+=v1[i]==tim?b1[i]:;
return ret;
} int Que(int l,int r){
return Query(r)-Query(l-);
} void Solve(int h,int t,int l,int r){
if(h>t)return;
if(l==r){
for(int i=h;i<=t;i++)
ans[p[i].id]=l;
return;
}
int mid=(l+r)>>;
int ct1=h,ct2=h;++tim;
for(int i=h;i<=t;i++){
if(p[i].tp==){
if(p[i].k>mid)continue;
Update(p[i].l,p[i].r,);
ct2+=;
}
else{
p[i].tmp=Que(p[i].l,p[i].r);
if(p[i].tmp>=p[i].k)ct2+=;
}
}
for(int i=h;i<=t;i++){
if(p[i].tp==){
if(p[i].k>mid)tmp[ct2++]=p[i];
else tmp[ct1++]=p[i];
}
else{
if(p[i].tmp>=p[i].k)tmp[ct1++]=p[i];
else p[i].k-=p[i].tmp,tmp[ct2++]=p[i];
}
}
for(int i=h;i<=t;i++)p[i]=tmp[i];
Solve(h,ct1-,l,mid);Solve(ct1,t,mid+,r);
} int main(){
#ifndef ONLINE_JUDGE
freopen("zjoi13_sequence.in","r",stdin);
freopen("zjoi13_sequence.out","w",stdout);
#endif
scanf("%d%d",&n,&Q);
for(int i=;i<=Q;i++){
scanf("%d%d",&p[i].tp,&p[i].l);
scanf("%d%d",&p[i].r,&p[i].k);
if(p[i].tp==){
p[i].id=++cntQ;
p[i].k=Que(p[i].l,p[i].r)-p[i].k+;
}
else
Update(p[i].l,p[i].r,);
} Solve(,Q,,n); for(int i=;i<=cntQ;i++)
printf("%d\n",ans[i]);
return ;
}
数据结构(树套树):ZJOI 2013 K大数查询的更多相关文章
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 解题:ZJOI 2013 K大数查询
题面 树套树,权值线段树套序列线段树,每次在在权值线段树上的每棵子树上做区间加,查询的时候左右子树二分 本来想两个都动态开点的,这样能体现树套树在线的优越性.但是常数太大惹,所以外层直接固定建树了QA ...
- [ZJOI 2013] K大数查询
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3110 [算法] 整体二分 + 线段树 时间复杂度 : O(NlogN ^ 2) [代 ...
- [BZOJ 3110] [ZJOI 2013] K大数查询
Description 有 \(N\) 个位置,\(M\) 个操作.操作有两种,每次操作如果是: 1 a b c:表示在第 \(a\) 个位置到第 \(b\) 个位置,每个位置加入一个数 \(c\): ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- ZJOI2013 K大数查询 和 LG3380【模板】二逼平衡树(树套树)
K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c:如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的 ...
- BZOJ 3110 k大数查询 & 树套树
题意: 有n个位置,每个位置可以看做一个集合,现在要求你实现一个数据结构支持以下功能: 1:在a-b的集合中插入一个数 2:询问a-b集合中所有元素的第k大. SOL: 调得火大! 李建说数据结构题能 ...
随机推荐
- oracle过滤分割字符串自定义函数
该函数实现过滤前后的指定的字符串,诸如过滤分隔符等.可用于过滤字符串中的逗号分割符.特别说明:substr()函数支持从字符串倒数开始读取,例如: dbms_output.put_line( subs ...
- C#快速排序法
最近面试的时候,被问到了快速排序法.一时之间,无法想起算法来. 重新看了书本,算法如下: 1)设置两个变量I.J,排序开始的时候:I=0,J=N-1: 2)以第一个数组元素作为关键数据,赋值给key, ...
- MVC+EF 的增删改查操作
1. //创建EF映射对象数据集 static Models.db_JiaoYouEntities DbDeleteData = new Models.db_JiaoYouEntities(); 2. ...
- UTF-8和GBK有什么区别?
字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1. 至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码.对于英文字符 ...
- Strut2 采用token机制防御CSRF同时也可以防止表单重复提交
一 未配置Struts2 token的情况下测试 1.从表单提交数据,可以从下图看出,快速点击保存按钮,请求提交了两次 2.检查post提交的数据中未含有token参数 3.查看数据列表,有重复数据 ...
- Vijos1834 NOI2005 瑰丽华尔兹 动态规划 单调双端队列优化
设dp[t][x][y]表示处理完前t个时间段,钢琴停留在(x,y)处,最多可以走多少个格子 转移时只需逆着当前倾斜的方向统计len个格子(len为时间区间的长度,len=t-s+1),如果遇到障碍就 ...
- 代码bug
1.webstorm ide未配置basePath本地会加入根路径 2.点击一次就销毁可以给标签设置一个值data-val="0" 某个函数只执行一次的方法,或者也可以考虑绑用on ...
- dedecms 常用标签调用
/*------------------单个ip调用-------------------*/ {dede:type typeid="12"} <a title=" ...
- PhotoSwipe.js 相册展示插件学习
PhotoSwipe.js官网:http://photoswipe.com/,在这个网站上可以下载到PhotoSwipe的文件以及相关的例子. 这个组件主要是用来展示图片.相册用的,还是很实用的. 一 ...
- Ubuntu软件包管理命令全面集锦
说明:由于图形化界面方法(如Add/Remove... 和Synaptic Package Manageer)比较简单,所以这里主要总结在终端通过命令行方式进行的软件包安装.卸载和删除的方法. 一.U ...