bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110
外层权值线段树套内层区间线段树;
之所以外层权值内层区间,是因为区间线段树需要标记下传,所以写在内层比较方便;
然而空间太大了,所以动态开点,大约每个外层线段树的点上有 logn 个内层线段树点;
最开始写的不知为何很快就WA:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=5e4+,maxm=maxn*;
int n,m,rt[maxn<<],ls[maxm],rs[maxm],cnt;
int a[maxn],b[maxn],tp[maxn],c[maxn],tmp[maxn],tot;
ll sum[maxm],lzy[maxm];//ll lzy 防止计算时爆int
void pushdown(int x,int l,int r)
{
if(!lzy[x])return;
if(!ls[x])ls[x]=++cnt;
if(!rs[x])rs[x]=++cnt;
int mid=((l+r)>>);
sum[ls[x]]+=(mid-l+)*lzy[x]; sum[rs[x]]+=(r-mid)*lzy[x];
lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
lzy[x]=;
}
void add(int &x,int l,int r,int L,int R)
{
if(!x)x=++cnt;
if(l>=L&&r<=R){sum[x]+=(r-l+); lzy[x]++; return;}
// pushdown(x,l,r);
int mid=((l+r)>>);
if(mid>=L)add(ls[x],l,mid,L,R);
if(mid<R)add(rs[x],mid+,r,L,R);
sum[x]=sum[ls[x]]+sum[rs[x]];
}
void insert(int x,int l,int r,int tl,int tr,int c)
{
add(rt[x],,n,tl,tr);
if(l==r)return;//
int mid=((l+r)>>);//权值区间
if(c<=mid)insert(x<<,l,mid,tl,tr,c);
else insert(x<<|,mid+,r,tl,tr,c);
}
ll ask(int x,int l,int r,int L,int R)
{
if(!x)return ;//
if(l>=L&&r<=R)return sum[x];
pushdown(x,l,r);
int mid=((l+r)>>); ll ret=;
// if(mid>=L)ret+=ask(x<<1,l,mid,L,R);
// if(mid<R)ret+=ask(x<<1|1,mid+1,r,L,R);
if(mid>=L)ret+=ask(ls[x],l,mid,L,R);
if(mid<R)ret+=ask(rs[x],mid+,r,L,R);//别写串了!
return ret;
}
int query(int x,int l,int r,int L,int R,int k)
{
if(l==r)return l;
ll tmp=ask(rt[x<<|],,n,L,R),mid=((l+r)>>);//查询第k大
if(tmp>=k)return query(x<<|,mid+,r,L,R,k);//
else return query(x<<,l,mid,L,R,k-tmp);//
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d%d",&tp[i],&a[i],&b[i],&c[i]);
if(tp[i]==)tmp[++tot]=c[i];
}
sort(tmp+,tmp+n+); tot=unique(tmp+,tmp+n+)-tmp-;
for(int i=;i<=m;i++)
{
if(tp[i]==)
{
int tt=lower_bound(tmp+,tmp+tot+,c[i])-tmp;
insert(,,tot,a[i],b[i],tt);
}
else printf("%d\n",tmp[query(,,tot,a[i],b[i],c[i])]);
}
return ;
}
囧
不会改了,所以模仿别人写了个标记永久化,然后WA惨;
因为不太熟悉标记永久化,没注意到更新以及查询时要注意不能重复,改了半天,终于好了...
学到了点标记永久化的细节。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=5e4+,maxm=maxn*;
int n,m,rt[maxn<<],ls[maxm],rs[maxm],cnt;
int a[maxn],b[maxn],tp[maxn],c[maxn],tmp[maxn],tot,L,R;
ll sum[maxm],lzy[maxm];//ll lzy 防止计算时爆int
//void pushdown(int x,int l,int r)
//{
// if(!lzy[x])return;
// if(!ls[x])ls[x]=++cnt;
// if(!rs[x])rs[x]=++cnt;
// int mid=((l+r)>>1);
// sum[ls[x]]+=(mid-l+1)*lzy[x]; sum[rs[x]]+=(r-mid)*lzy[x];
// lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
// lzy[x]=0;
//}
void add(int &x,int l,int r,int L,int R)
{
if(!x)x=++cnt;
if(l==L&&r==R){/*sum[x]+=(r-l+1);*/ lzy[x]++; return;}//==
sum[x]+=(R-L+);
// pushdown(x,l,r);
int mid=((l+r)>>);
// if(mid>=L)add(ls[x],l,mid,L,R);//会重复计算sum!(因为标记永久化)
// if(mid<R)add(rs[x],mid+1,r,L,R);
// sum[x]=sum[ls[x]]+sum[rs[x]];
if(mid<L)add(rs[x],mid+,r,L,R);
else if(mid>=R)add(ls[x],l,mid,L,R);
else add(ls[x],l,mid,L,mid),add(rs[x],mid+,r,mid+,R);
}
ll ask(int x,int l,int r,int L,int R)
{
if(!x)return ;//
ll ret=lzy[x]*(R-L+);
if(l==L&&r==R)return ret+sum[x];//
// pushdown(x,l,r);
int mid=((l+r)>>);
// if(mid>=L)ret+=ask(x<<1,l,mid,L,R);
// if(mid<R)ret+=ask(x<<1|1,mid+1,r,L,R);//别把ls,rs和x<<1,x<<1|1写串了!
// if(mid>=L)ret+=ask(ls[x],l,mid);
// if(mid<R)ret+=ask(rs[x],mid+1,r); //会重复计算!!
// printf("ret=%lld\n",ret);
if(mid<L)return ret+ask(rs[x],mid+,r,L,R);
else if(mid>=R)return ret+ask(ls[x],l,mid,L,R);
else return ret+ask(ls[x],l,mid,L,mid)+ask(rs[x],mid+,r,mid+,R);
}
int query(int x,int l,int r,int k)
{
if(l==r)return l;
ll tmp=ask(rt[x<<|],,n,L,R),mid=((l+r)>>);//查询第k大
if(tmp>=k)return query(x<<|,mid+,r,k);//
else return query(x<<,l,mid,k-tmp);//
}
void insert(int x,int l,int r,int c)
{
add(rt[x],,n,L,R);
if(l==r)return;//
int mid=((l+r)>>);//权值区间
if(c<=mid)insert(x<<,l,mid,c);
else insert(x<<|,mid+,r,c);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d%d",&tp[i],&a[i],&b[i],&c[i]);
if(tp[i]==)tmp[++tot]=c[i];
}
sort(tmp+,tmp+n+); tot=unique(tmp+,tmp+n+)-tmp-;
for(int i=;i<=m;i++)
{
L=a[i],R=b[i];
if(tp[i]==)
{
int tt=lower_bound(tmp+,tmp+tot+,c[i])-tmp;
insert(,,tot,tt);
}
else printf("%d\n",tmp[query(,,tot,c[i])]);
}
return ;
}
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大数查询 【树套树,标记永久化】
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 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大数查询 【cdq分治&树套树】
模板题,折腾了许久. cqd分治整体二分,感觉像是把询问分到答案上. #include <bits/stdc++.h> #define rep(i, a, b) for (int i = ...
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- [BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- 【树套树】bzoj3110 [Zjoi2013]K大数查询
题解很多,实现起来以外地简洁.内层的区间线段树上用了标记永久化. #include<cstdio> using namespace std; #define N 50001 struct ...
随机推荐
- JS——try catch throw
本例检测输入变量的值.如果值是错误的,会抛出一个异常(错误).catch 会捕捉到这个错误,并显示一段自定义的错误消息: <script> function myFunction() { ...
- iOS实现图形编程可以使用三种API(UIKIT、Core Graphics、OpenGL ES及GLKit)
这些api包含的绘制操作都在一个图形环境中进行绘制.一个图形环境包含绘制参数和所有的绘制需要的设备特定信息,包括屏幕图形环境.offscreen 位图环境和PDF图形环境,用来在屏幕表面.一个位图或一 ...
- CAD调用移动命令
主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数,详细说明如下: 参数 说明 IDispatch* pParam 命令参数,IMx ...
- 怎么用最短时间高效而踏实地学习Linux?
在技术行业里,人才的唯一衡量标准就是技术能力,而技术能力,就代表着你的薪资.职位.话语权.很多人都经历过,跟自己同时入行甚至入行还晚的人,成长速度却远超自己,短短两三年就拉开了差距. 秘密就在于,有些 ...
- 通过JS唤醒app(安卓+ios)
有需求说要通过页面按钮唤醒app,或者手机上没有这款app跳转到商店,然后刚开始也是查了资料的,结果发现一头雾水,不过最后还是捣鼓出来了,当然也参考了前人分享的经验,下面我就将方法整理一下: 首先明确 ...
- 51nod1006 -最长公共子序列Lcs【动态规划】
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最 ...
- uva340 Master-Mind Hints (UVA - 340)
题目简要 题目意思很简单每个测试都由原题目在第一行,然后后面的都是去猜的答案,如果猜测的位置正确那么输出的结果的数对里面的第一个数就加一,如果仅答案正确(原题目里有这个数,但是位置不一样)那么就在输出 ...
- nginx的安装部署以及使用
[介绍] nginx是现在互联上非常流行的高性能的 Web 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. 现在很多互联网应用都使用nginx来作为负载均衡的使用,再高并发 ...
- Spark源码值提交任务
/** * Return the number of elements in the RDD. */ def count(): Long = sc.runJob(this, Utils.getIt ...
- 20180629利用powerdesigner生成数据字典
原创作品,如有错误,请批评指正 第一步新建一个PDM模型 第二步 点击“FILE”--->"RESERVER ENGINEER"--->"DATABASE&q ...