洛谷题面传送门

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. 成功在Caterpillar代码中插入事件对象-20200917

    首先搞清楚了Caterpillar的solidity代码生成机制.Caterpillar分为Caterpillar Core和 executepanel两部分. executePanel是UI前端,用 ...

  2. Spark RDD编程(博客索引,日常更新)

    本篇主要是记录自己在中解决RDD编程性能问题中查阅的论文博客,为我认为写的不错的建立索引方便查阅,我的总结会另立他篇 1)通过分区(Partitioning)提高spark性能https://blog ...

  3. vue介绍啊

    声明式渲染:vue的核心是一个允许你才用一个简洁的模板语法来声明式的将数据渲染进行DOM的系统 html部分:<div id="app"> {{message}}< ...

  4. RogrePirates Scrum Meeting 博客汇总

    RogrePirates 博客目录 一.Scrum Meeting 1.Alpha阶段 第一次会议 第二次会议 第三次会议 第四次会议 第五次会议 第六次会议 第七次会议 第八次会议 第九次会议 第十 ...

  5. $dy$讲课总结

    字符串: 1.广义后缀自动机(大小为\(m\))上跑一个长度为\(n\)的串,所有匹配位置及在\(parent\)树上其祖先的数量的和为\(min(n^2,m)\),单次最劣是\(O(m)\). 但是 ...

  6. sort方法和自定义比较器的写法

    摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collections.sort()方法.对自定义对象排序 ...

  7. Envoy实现.NET架构的网关(二)基于控制平面的动态配置

    什么是控制平面 上一篇我们讲了文件系统的动态配置,这次我们来看看通过Control Panel来配置Envoy.控制平面就是一个提供Envoy配置信息的单独服务,我们可以通过这个服务来修改Envoy的 ...

  8. xUtils3的使用教程

    首先在build.gradle下的dependencies下添加引用. implementation 'org.xutils:xutils:3.3.36' 然后创建一个表实体. package com ...

  9. linux 内核源代码情景分析——几个重要的数据结构和函数

    页面目录PGD.中间目录PMD和页面表PT分别是由表项pgd_t.pmd_t和pte_t构成的数组,而这些表项都是数据结构 1 /* 2 * These are used to make use of ...

  10. mybatis之结果集的映射方式

    查询的几种情况 // 1)查询单行数据返回单个对象 public Employee getEmployeeById(Integer id ); // 2) 查询多行数据返回对象的集合 public L ...