洛谷题面传送门

KDT 上打标记的 hot tea。

考虑将询问 \(A,B\) 看作二维平面直角坐标系上的一个点 \((A,B)\),那么我们这样考虑,我们从左到右扫过全部 \(n\) 个区间并开一个变量 \(cnt\) 表示当前与 \([l_i,r_i]\) 有交的区间的最大长度,如果当前扫描到的区间 \([l_i,r_i]\) 与区间 \([A,B]\) 有交,那么我们就令 \(cnt\) 加 \(1\),否则 \(cnt\) 清空,答案就是任意时刻最大的 \(cnt\)。

显然如果我们暴力地对所有区间都重复一遍这个操作那时间复杂度肯定爆炸,考虑如何优化,我们将所有询问离线下来并一遍扫过全部 \(n\) 个区间处理所有询问,不难发现对于一个区间 \([l_i,r_i]\) 而言,与其没有交的询问对应的点肯定会落在两个矩形内,因此我们每次需要做的即是:

  • 将某两个矩形中所有点的权值清零。
  • 将不在这两个矩形中的所有点权值加一

最后要求的即是每个节点权值的历史最大值。

考虑对这 \(m\) 个询问点建立 KDT,那么根据 KDT 那一套理论,我们可以将矩形上的操作转化为 \(\sqrt{n}\) 个单点操作 \(+\) \(\sqrt{n}\) 个子树操作。单点操作是容易的,难点在于子树操作,因此我们现在要实现的即为:

  • 将子树内所有点权值清零
  • 将子树内所有点权值加一

对求解历史最大值线段树比较了解的同学到这一步应该会做了。但是我对理是最大值线段树不是太了解,因此这里会较为详细地讲解一下如何用历史最大值的标记解决这个问题。我们考察一个点上一次标记下推到现在一共经历了哪些过程,有两种可能,要么没有被清空,权值直接被加上了一个数 \(v\)。要么曾经被清空过,一开始先 \(+v_0\),然后清空,又加了 \(v_1\),再清空,\(+v_2\),清空,……,最后 \(+v_m\),值为 \(v_m\)。不难发现由于我们只关心历史最大值,因此 \(v_1,v_2,\cdots,v_m\) 具体是什么不重要,我们只用关心以下几个值:

  • 第一次加的值 \(v_0\),程序中用 \(add\_mx\) 表示。
  • 这个值从上一次被标记下推是否被清空,\(clr\)。
  • \(\max{v_1,v_2,\cdots,v_m}\),程序中用 \(cov\_mx\) 表示。
  • 这个位置当前的值 \(v_m\),程序中用 \(tg\) 表示。

当然除了这四个标记之外,还有每个位置的权值 \(v\) 以及历史最大值 \(hmx\)。

考虑对一个子树清空/整体加值会对标记产生怎样的影响。首先是子树清空,这个比较容易,直接将 \(clr\) 设为 \(1\),\(tg,v\) 设为 \(0\) 即可。其次是整体加值,如果 \(clr\ne 0\) 那就令 \(tg\) 加 \(v\),并将 \(cov\_mx\) 对 \(tg\) 取 \(\max\),否则令 \(add\_mx\) 加 \(v\)。

然后是下推标记的问题,如果 \(clr=0\) 那么直接对左右儿子进行整体 \(+add\_mx\) 操作即可。否则操作等价于先对左右儿子进行 \(+add\_mx\),然后 \(+v_1\),清空,\(+v_2\),清空,……,最后 \(+v_m\),这等价于先对左右儿子进行整体 \(+add\_mx\) 操作,然后令左右儿子的 \(cov\_mx\) 对该节点的 \(cov\_mx\) 取 \(\max\),然后令左右儿子的 \(tg\) 和 \(v\) 都等于 \(tg\)。注意每次操作之后都要实时更新 \(hmx\)。

时间复杂度 \(n\sqrt{m}\)。

const int MAXN=2e5;
const int K=2;
int n,m,res[MAXN+5];pii a[MAXN+5];
struct point{
int x[K+2],id;
point(){memset(x,0,sizeof(x));id=0;}
int& operator [](int id){return x[id];}
} p[MAXN+5];
struct node{int ch[2],v,hmx,add_mx,cov_mx,tg,clr;point val,mn,mx;} s[MAXN+5];
int ncnt=0,rt=0;
void build(int &k,int l,int r){
if(l>r) return;k=++ncnt;
static double avg[K+2],var[K+2];
fill(avg,avg+K,0);fill(var,var+K,0);
for(int i=l;i<=r;i++) for(int j=0;j<K;j++) avg[j]+=p[i][j];
for(int j=0;j<K;j++) avg[j]/=(r-l+1);
for(int i=l;i<=r;i++) for(int j=0;j<K;j++) var[j]+=(p[i][j]-avg[j])*(p[i][j]-avg[j]);
double mx=0;int dim=0;
for(int j=0;j<K;j++) if(mx<var[j]) mx=var[j],dim=j;
int mid=l+r>>1;
nth_element(p+l,p+mid,p+r+1,[&](point x,point y){return x[dim]<y[dim];});
build(s[k].ch[0],l,mid-1);build(s[k].ch[1],mid+1,r);
s[k].val=s[k].mn=s[k].mx=p[mid];
for(int i=0;i<K;i++){
if(s[k].ch[0]) chkmin(s[k].mn[i],s[s[k].ch[0]].mn[i]),chkmax(s[k].mx[i],s[s[k].ch[0]].mx[i]);
if(s[k].ch[1]) chkmin(s[k].mn[i],s[s[k].ch[1]].mn[i]),chkmax(s[k].mx[i],s[s[k].ch[1]].mx[i]);
}
}
void tagclr(int k){s[k].clr=1;s[k].tg=0;s[k].v=0;}
void tagadd(int k,int v){
s[k].v+=v;chkmax(s[k].hmx,s[k].v);s[k].tg+=v;
if(s[k].clr) chkmax(s[k].cov_mx,s[k].tg);
else chkmax(s[k].add_mx,s[k].tg);
}
void pushdown(int k){
if(s[k].add_mx){
if(s[k].ch[0]) tagadd(s[k].ch[0],s[k].add_mx);
if(s[k].ch[1]) tagadd(s[k].ch[1],s[k].add_mx);
s[k].add_mx=0;
} if(s[k].clr){
if(s[k].ch[0]){
s[s[k].ch[0]].clr=1;
chkmax(s[s[k].ch[0]].cov_mx,s[k].cov_mx);
chkmax(s[s[k].ch[0]].hmx,s[k].cov_mx);
s[s[k].ch[0]].tg=s[k].tg;
s[s[k].ch[0]].v=s[k].tg;
} if(s[k].ch[1]){
s[s[k].ch[1]].clr=1;
chkmax(s[s[k].ch[1]].cov_mx,s[k].cov_mx);
chkmax(s[s[k].ch[1]].hmx,s[k].cov_mx);
s[s[k].ch[1]].tg=s[k].tg;
s[s[k].ch[1]].v=s[k].tg;
} s[k].cov_mx=s[k].clr=0;
} s[k].tg=0;
}
void clrpt(int k){pushdown(k);s[k].v=0;}
void addpt(int k,int v){pushdown(k);s[k].v+=v;chkmax(s[k].hmx,s[k].v);}
void modify(int k,int l,int r){
if(!k) return;
if(s[k].mn[0]>r||s[k].mx[1]<l) return tagclr(k),void();
if(l<=s[k].mn[1]&&s[k].mx[0]<=r) return tagadd(k,1),void();
pushdown(k);
if(s[k].val[0]>r||s[k].val[1]<l) clrpt(k);
else addpt(k,1);
modify(s[k].ch[0],l,r);modify(s[k].ch[1],l,r);
}
void dfs(int k){
if(!k) return;res[s[k].val.id]=s[k].hmx;
pushdown(k);dfs(s[k].ch[0]);dfs(s[k].ch[1]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].fi,&a[i].se);
for(int i=1;i<=m;i++) scanf("%d%d",&p[i][0],&p[i][1]),p[i].id=i;
build(rt,1,m);
for(int i=1;i<=n;i++) modify(rt,a[i].fi,a[i].se);
dfs(rt);
for(int i=1;i<=m;i++) printf("%d\n",res[i]);
return 0;
}
/*
8 2
4 5
5 6
2 4
1 3
5 7
6 7
1 6
2 5
4 7
4 5
*/

洛谷 P6349 - [PA2011]Kangaroos(KDT+标记下放)的更多相关文章

  1. 题解 洛谷 P6349 【[PA2011]Kangaroos】

    先考虑对题目进行转化,我们称两个区间有交集为这两个区间能匹配,每个询问就是在序列中最长能连续匹配的长度. 对序列中的一个区间\([l,r]\)和询问的一个区间\([L,R]\),若满足\(L \leq ...

  2. 洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分

    题目:https://www.luogu.org/problemnew/show/P1083 听说线段树不标记永久化会T一个点. 注意mn记录的是本层以下.带上标记的min! #include< ...

  3. 【洛谷1501】[国家集训队] Tree II(LCT维护懒惰标记)

    点此看题面 大致题意: 有一棵初始边权全为\(1\)的树,四种操作:将两点间路径边权都加上一个数,删一条边.加一条新边,将两点间路径边权都加上一个数,询问两点间路径权值和. 序列版 这道题有一个序列版 ...

  4. 洛谷 P6783 - [Ynoi2008] rrusq(KDT+势能均摊+根号平衡)

    洛谷题面传送门 首先显然原问题严格强于区间数颜色,因此考虑将询问离线下来然后用某些根号级别复杂度的数据结构.按照数颜色题目的套路,我们肯定要对于每种颜色维护一个前驱 \(pre\),那么答案可写作 \ ...

  5. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  6. 洛谷 P3391 【模板】文艺平衡树(Splay)

    题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...

  7. 【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)

    洛谷P2023:https://www.luogu.org/problemnew/show/P2023 思路 需要2个Lazy-Tag 一个表示加的 一个表示乘的 需要先计算乘法 再计算加法 来自你谷 ...

  8. [洛谷P2023] [AHOI2009]维护序列

    洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...

  9. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

随机推荐

  1. 最详细的Android SDK下载安装及配置教程-------全文均为引用

    <https://www.cnblogs.com/gufengchen/p/11038029.html>

  2. Java:反射小记

    Java:反射小记 对 Java 中的 反射,做一个微不足道的小小小小记 概念 Java 反射指的是在 Java 程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法:对于给定的一个对象, ...

  3. NKOJ-2936 城市建设

    问题描述: PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁.Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费.Louis希望建造最少的道路使得国 ...

  4. RAW RGB格式

    RAW RGB格式 10bit Raw RGB, 就是说用10bit去表示一个R, G, 或者B, 通常的都是用8bit的. 所以你后面处理时要把它转换为8bit的, 比较简单的方法就是将低两位去掉, ...

  5. 禁用root直接远程登录,使用普通账号登录后再切换root

    1.创建一个普通用户 #useradd test 2.给test设置密码 #passwd test 3.禁用root远程登录 #vim /etc/ssh/sshd_config #PermitRoot ...

  6. vivo 全球商城:商品系统架构设计与实践

    一.前言 随着用户量级的快速增长,vivo官方商城v1.0的单体架构逐渐暴露出弊端:模块愈发臃肿.开发效率低下.性能出现瓶颈.系统维护困难. 从2017年开始启动的v2.0架构升级,基于业务模块进行垂 ...

  7. LeetCode88 合并有序数组

    1. 这道题为简单题目,但是还有需要好好思考的 2. 首先不能使用额外数组合并,不然就没得后文了 3. nums1后面有0填充,且填充数量正好是n,整个数组大小即m+n能够容纳合并后的数据 4.既然要 ...

  8. Go语言并发模型 G源码分析

    Go 的线程实现模型,有三个核心的元素 M.P.G,它们共同支撑起了这个线程模型的框架.其中,G 是 goroutine 的缩写,通常称为 "协程".关于协程.线程和进程三者的异同 ...

  9. C# | VS2019连接MySQL的三种方法以及使用MySQL数据库教程

    本文将介绍3种添加MySQL引用的方法,以及连接MySQL和使用MySQL的教程 前篇:Visual Studio 2019连接MySQL数据库详细教程 \[QAQ \] 第一种方法 下载 Mysql ...

  10. RabbitMQ保证消息的顺序性

    当我们的系统中引入了MQ之后,不得不考虑的一个问题是如何保证消息的顺序性,这是一个至关重要的事情,如果顺序错乱了,就会导致数据的不一致.       比如:业务场景是这样的:我们需要根据mysql的b ...