洛谷 P6349 - [PA2011]Kangaroos(KDT+标记下放)
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+标记下放)的更多相关文章
- 题解 洛谷 P6349 【[PA2011]Kangaroos】
先考虑对题目进行转化,我们称两个区间有交集为这两个区间能匹配,每个询问就是在序列中最长能连续匹配的长度. 对序列中的一个区间\([l,r]\)和询问的一个区间\([L,R]\),若满足\(L \leq ...
- 洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分
题目:https://www.luogu.org/problemnew/show/P1083 听说线段树不标记永久化会T一个点. 注意mn记录的是本层以下.带上标记的min! #include< ...
- 【洛谷1501】[国家集训队] Tree II(LCT维护懒惰标记)
点此看题面 大致题意: 有一棵初始边权全为\(1\)的树,四种操作:将两点间路径边权都加上一个数,删一条边.加一条新边,将两点间路径边权都加上一个数,询问两点间路径权值和. 序列版 这道题有一个序列版 ...
- 洛谷 P6783 - [Ynoi2008] rrusq(KDT+势能均摊+根号平衡)
洛谷题面传送门 首先显然原问题严格强于区间数颜色,因此考虑将询问离线下来然后用某些根号级别复杂度的数据结构.按照数颜色题目的套路,我们肯定要对于每种颜色维护一个前驱 \(pre\),那么答案可写作 \ ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- 洛谷 P3391 【模板】文艺平衡树(Splay)
题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...
- 【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
洛谷P2023:https://www.luogu.org/problemnew/show/P2023 思路 需要2个Lazy-Tag 一个表示加的 一个表示乘的 需要先计算乘法 再计算加法 来自你谷 ...
- [洛谷P2023] [AHOI2009]维护序列
洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
随机推荐
- find+xargs+sed批量替换
写代码时经常遇到要把 .c 和 .h的文件中的某些内容全部替换的情况,用sourceinsight 进行全局的查找是一个方法,但是sourceinsight只能替换一个文件中的字符串,不能同时替换多 ...
- 利用python爬取全国水雨情信息
分析 我们没有找到接口,所以打算利用selenium来爬取. 代码 import datetime import pandas as pd from bs4 import BeautifulSoup ...
- 微信小程序中路由跳转
一.是什么 微信小程序拥有web网页和Application共同的特征,我们的页面都不是孤立存在的,而是通过和其他页面进行交互,来共同完成系统的功能 在微信小程序中,每个页面可以看成是一个pageMo ...
- 【UE4 C++】 射线检测 LineTrace 及 BoxTrace、SphereTrace、CapsuleTrace API
World.h 库里的 Trace API Trace模式 TraceSingle 单个结果 TraceMulti 多个结果 Trace 的检测依据 ByChanne ByObjectType ByP ...
- 【数据结构与算法Python版学习笔记】树——二叉查找树 Binary Search Tree
二叉搜索树,它是映射的另一种实现 映射抽象数据类型前面两种实现,它们分别是列表二分搜索和散列表. 操作 Map()新建一个空的映射. put(key, val)往映射中加入一个新的键-值对.如果键已经 ...
- Beta阶段第十次会议
Beta阶段第十次会议 时间:2020.5.26 完成工作 姓名 完成工作 难度 完成度 ltx 1.修正小程序新闻bug2.修正小程序认证bug 中 80% xyq 1.上传信息编辑部分代码到服务器 ...
- Qt字符编码小知识
1.VS2010默认编码是GBK,Qt5的内置编码是utf-8,想要在VS2010及其以上版本,优雅的使用utf-8的字符编码需要 // Coding: UTF-8(BOM) #if defined( ...
- iPhone SE切换颜色特效
Apple 网站的特效, iPhone SE 共有黑.白.红三种颜色,在卷动页面的时候会逐步替换,看起来效果非常时尚,在此供上代码学习. <!DOCTYPE html> <html& ...
- Vue | uni-app 中使用websocket
@ 目录 首先在根目录下新建一个store文件夹,并新建一个websocket.js文件,代码如下: import Vue from 'vue' import Vuex from 'vuex' Vue ...
- ICMP 协议仿真及ping命令用途
1.实验目的 加深对 IPv4 协议首部各定义域的理解,掌握路由表的结构和基本配置命令,熟悉 ICMP 的调试操作. 2.实验原理 IPv4 协议定义,网络层协议的相关 RFC 定义和描述. 3.实验 ...