bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110
第一道线段树套线段树!
第一道标记永久化!
为什么为什么写了两个半小时啊……
本想线段树套平衡树,但想不出怎么合并不同区间上的平衡树(LCT??)。
于是看了一下Zinn的TJ。原来是线段树套线段树呀。原来外层是权值内层是区间呀。原来要动态开点呀。
这是因为区间线段树要下传标记什么的,而权值线段树在本题中都是在叶子上修改。所以这样比较方便。
然后手胡了一番pshp,pshd。RE到飞起。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- const int N=5e4,M=1e5+;
- int n,m,tt1,tt2,rtt,rt[M<<],ls[M<<],rs[M<<],L,R;
- struct Node{
- int ls,rs;long long lazy,sum;//ll!
- }a[N*+];//每个外层点上有logn个节点
- void pshd2(int cr,int &l,int &r,int lb,int rb)
- {
- if(!l)l=++tt2;if(!r)r=++tt2;//!!
- if(!a[cr].lazy)return;
- int w=a[cr].lazy,mid=lb+rb>>;
- a[cr].lazy=;a[l].lazy+=w;a[r].lazy+=w;
- a[l].sum+=w*(mid-lb+);a[r].sum+=w*(rb-mid);
- }
- void pshp2(int cr)
- {
- a[cr].sum=a[a[cr].ls].sum+a[a[cr].rs].sum;
- }
- void pshp1(int &cr,int p1,int p2)
- {
- if(!cr)cr=++tt2;
- a[cr].sum=a[p1].sum+a[p2].sum;
- a[cr].lazy=a[p1].lazy+a[p2].lazy;
- if(a[p1].ls||a[p2].ls)pshp1(a[cr].ls,a[p1].ls,a[p2].ls);
- if(a[p1].rs||a[p2].rs)pshp1(a[cr].rs,a[p1].rs,a[p2].rs);
- }
- void mdfy(int l,int r,int &cr)
- {
- if(!cr)cr=++tt2;
- if(l>=L&&r<=R){a[cr].sum+=(r-l+);a[cr].lazy++;return;}//r-l+1!!
- pshd2(cr,a[cr].ls,a[cr].rs,l,r);int mid=l+r>>;
- if(L<=mid)mdfy(l,mid,a[cr].ls);
- if(mid<R)mdfy(mid+,r,a[cr].rs);
- pshp2(cr);
- }
- void mdfy(int l,int r,int &cr,int p)
- {
- if(!cr)cr=++tt1;
- if(l==r){mdfy(,n,rt[cr]);return;}
- int mid=l+r>>;
- if(p<=mid)mdfy(l,mid,ls[cr],p);
- else mdfy(mid+,r,rs[cr],p);
- pshp1(rt[cr],rt[ls[cr]],rt[rs[cr]]);
- //别pshp了,标记永久化
- }
- int query(int l,int r,int cr)
- {
- // printf("l=%d r=%d L=%d R=%d a[%d].sum=%d\n",l,r,L,R,cr,a[cr].sum);
- if(l>=L&&r<=R)return a[cr].sum;
- pshd2(cr,a[cr].ls,a[cr].rs,l,r);int mid=l+r>>;
- if(L>mid)return query(mid+,r,a[cr].rs);
- if(R<=mid)return query(l,mid,a[cr].ls);
- return query(l,mid,a[cr].ls)+query(mid+,r,a[cr].rs);
- }
- int query(int l,int r,int cr,int k)
- {
- if(l==r)return l;
- int mid=l+r>>;
- int w=query(,n,rt[rs[cr]]);
- // printf("l=%d r=%d mid=%d w=%d\n",l,r,mid,w);
- if(w>=k)return query(mid+,r,rs[cr],k);
- else return query(l,mid,ls[cr],k-w);
- }
- int main()
- {
- scanf("%d%d",&n,&m);int op,c;
- while(m--)
- {
- scanf("%d%d%d%d",&op,&L,&R,&c);
- if(op==)
- mdfy(-N,N,rtt,c);
- else
- printf("%d\n",query(-N,N,rtt,c));
- }
- return ;
- }
然后又看看Zinn的TJ。原来是标记永久化呀。抄抄抄。
标记永久化就是没有pshp和pshd。在修改的时候往下走的时候就把sum改掉(因为改sum需要知道区间大小,所以需要传L,R),不往下走的时候同样打上lazy。在查询的时候把路径上的lazy累加。细节是累加的lazy需要乘上目标区间的大小,而且因为这种写法,打lazy的时候就不能加sum了。
仍旧数组大小迷茫中。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define ll long long
- using namespace std;
- const int N=5e4+,M=N*;//
- int n,m,tt1,tt2,lm,rtt,ls[N<<],rs[N<<],rt[N<<],lss[M],rss[M];
- int L,R,op[N],x[N],y[N],c[N],tp[N];
- ll sum[M],lazy[M];//ll,防止计算时爆int
- void add(int l,int r,int &cr,int L,int R)//传L,R
- {
- if(!cr)cr=++tt2;
- if(l==L&&r==R){lazy[cr]++;return;}//==
- sum[cr]+=R-L+;//打了lazy就不要加sum了--看query那里
- int mid=l+r>>;
- if(mid<L)add(mid+,r,rss[cr],L,R);
- else if(mid>=R)add(l,mid,lss[cr],L,R);
- else add(l,mid,lss[cr],L,mid),add(mid+,r,rss[cr],mid+,R);
- }
- void insert(int l,int r,int &cr,int p)
- {
- if(!cr)cr=++tt1;
- add(,n,rt[cr],L,R);
- if(l==r)return;int mid=l+r>>;
- if(p<=mid)insert(l,mid,ls[cr],p);
- else insert(mid+,r,rs[cr],p);
- }
- //int query(int l,int r,int cr,ll lz)
- //{
- // if(l>=L&&r<=R)return sum[cr]+lz;
- // int mid=l+r>>1;int ret=0;
- // if(L<=mid)ret+=query(l,mid,lss[cr],lz+lazy[cr]);
- // if(mid<R)ret+=query(mid+1,r,rss[cr],lz+lazy[cr]);
- // return ret;
- //}
- ll query(int l,int r,int cr,int L,int R)//传L,R
- {
- if(!cr)return ;///////
- ll ret=(R-L+)*lazy[cr];//可以每次return加ret,就不用传参数
- if(l==L&&r==R)return ret+sum[cr];
- int mid=l+r>>;
- if(L>mid)return ret+query(mid+,r,rss[cr],L,R);
- if(R<=mid)return ret+query(l,mid,lss[cr],L,R);
- return ret+query(l,mid,lss[cr],L,mid)+query(mid+,r,rss[cr],mid+,R);//仔细想想只加一个ret!!!
- }
- int query(int l,int r,int &cr,int k)
- {
- if(!cr)cr=++tt1;//
- if(l==r)return l;
- ll w=query(,n,rt[rs[cr]],L,R),mid=l+r>>;
- if(w>=k)return query(mid+,r,rs[cr],k);
- else return query(l,mid,ls[cr],k-w);
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- for(int i=;i<=m;i++)
- {
- scanf("%d%d%d%d",&op[i],&x[i],&y[i],&c[i]);
- if(op[i]==)tp[++lm]=c[i];//only op==1!!!
- }
- sort(tp+,tp+m+);lm=unique(tp+,tp+m+)-tp-;
- for(int i=;i<=m;i++)
- {
- L=x[i];R=y[i];
- if(op[i]==)
- {
- int tmp=lower_bound(tp+,tp+lm+,c[i])-tp;
- insert(,lm,rtt,tmp);
- }
- else printf("%d\n",tp[query(,lm,rtt,c[i])]);
- }
- return ;
- }
bzoj 3110 [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大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 418 Solved: 235 [ Submit][ ...
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- 树套树专题——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大数查询( 树状数组套主席树 )
BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...
- BZOJ 3110 [Zjoi2013]K大数查询(整体二分)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 11654 Solved: 3505[Submit][St ...
- [BZOJ 3110] [Zjoi2013] K大数查询 【树套树】
题目链接: BZOJ - 3110 题目分析 这道题是一道树套树的典型题目,我们使用线段树套线段树,一层是区间线段树,一层是权值线段树.一般的思路是外层用区间线段树,内层用权值线段树,但是这样貌似会很 ...
- bzoj 3110 [Zjoi2013]K大数查询(树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)
题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...
随机推荐
- idea设置编码格式utf-8
settings >> File Encodings >>如下
- Amazon S3和EBS的区别
- (转)Nginx+Php-fpm运行原理详解
一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpn翻墙才能访问google.com. vpn对于“我们”来说,是可以感知到的(我 ...
- 【笔记篇】C#笔记3
笔记目录:http://blog.csdn.net/enzymii/article/details/77169928 C#的接口有点意思,我们说过可以用来多重继承.. using System; na ...
- Python全栈开发:css引入方式
css的四种引入方式: 1.行内式 行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐使用. <p style="color: red;backgr ...
- Ubuntu vi命令
最近在使用ubuntu,在linux下,要编辑文件或者其他的文本文件,哪那么一个ubuntu linux下的强大的文本编辑工具就不得不提了,那就是VI编辑器.下面把VI常用到的命令行贴出来. :w ...
- [JZOJ3177] 【GDOI2013模拟5】安全监控
题目 描述 (样例都懒得发出来了) 题目大意 给你一个有向图,从111号点出发,绕一圈回来.这一圈中必须经过222号点. 问经过的最少的点数(不重复). 思考历程 一看就觉得是一道神题. 然后仔细观察 ...
- 廖雪峰Java11多线程编程-2线程同步-2synchronized方法
1.Java使用synchronized对一个方法进行加锁 class Counter{ int count = 0; public synchronized void add(int n){ cou ...
- OpenCASCADE动画功能2
OpenCASCADE动画功能2 eryar@163.com OpenCASCADE是一个开发平台,主要提供三维曲面和实体建模.CAD数据交换及可视化等功能.OCCT最适用于开发三维建模CAD软件.加 ...
- Python学习day18-常用模块之NumPy
figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...