洛谷题面传送门

首先显然原问题严格强于区间数颜色,因此考虑将询问离线下来然后用某些根号级别复杂度的数据结构。按照数颜色题目的套路,我们肯定要对于每种颜色维护一个前驱 \(pre\),那么答案可写作 \(pre\ge l\) 的所有颜色的权值之和。此题也不例外。考虑将所有询问存在右端点,那么每次扫描一个矩形 \(i\),就将矩形中所有点被覆盖的时间设为 \(i\),那么 \([l,r]\) 区间的答案即为扫描到 \(r\) 时 \(pre\ge l\) 的点权之和。

考虑怎么维护 \(pre\),首先看到矩形以及这个 128M 的空间,显然不是让我们树套树而是让我们 2-DT 的,因此建出 2-DT,那么矩形覆盖即可转化为 \(\mathcal O(\sqrt{n})\) 个单点修改和 \(\mathcal O(\sqrt{n})\) 个子树整体修改,但是由于我们并不是简简单单地求出 \(pre\) 就完事了,我们还要求出 \(pre\) 值在一段区间内的点权之和,事情变得棘手起来……不过注意到这样一件事,对于单点修改显然如果原来有标记那就直接撤销贡献即可,对于子树整体修改,整体覆盖的点的子树都是不交的,而撤销贡献等价于“收回”标记,即打标记的逆操作。因此我们考虑对一个子树整体覆盖时,就暴力 DFS 整棵子树收回子树中所有标记,如果子树中没有标记那就 return,然后假设我们欲将矩形中所有点赋值为 \(v\),那么我们就建立一个数据结构并在这个数据结构下标为 \(v\) 的位置加上当前子树中所有点点权和。由于收回标记是打标记的逆操作,你暴力 DFS 的复杂度均摊下来肯定和打标记相同,因此这部分复杂度是 \(m\sqrt{n}\) 的。

接下来考虑怎样计算答案,通过上面的分析我们已经能够在较快时间内维护 \(pre\) 为某个值的点权之和的变化了,这样扫描到 \(r\) 时,我们只需做一遍区间求和即可求出区间 \([l,r]\) 的答案。那么用什么数据结构维护呢?根据根号平衡的思想,如果用树状数组那么复杂度 \(m\sqrt{n}\log n+q\log n\),导致复杂度向左倾,不知道能不能过。换成 \(\mathcal O(1)\) 单点加 \(\mathcal O(\sqrt{n})\) 求和的分块复杂度就是 \(m\sqrt{n}+q\sqrt{m}\),应该就比较稳了(

const int MAXN=1e5;
const int K=2;
const int BLK=317;
const int MAXQ=1e6;
int n,m,qu;
struct point{
int x[K+2],v;
point(){memset(x,0,sizeof(x));v=0;}
int& operator [](int id){return x[id];}
} p[MAXN+5];
struct node{int ch[2],tg,has_tag,tg_pt;ll sum;point val,mn,mx;} s[MAXN+5];
void pushup0(int k){s[k].sum=s[s[k].ch[0]].sum+s[s[k].ch[1]].sum+s[k].val.v;}
void pushup(int k){s[k].has_tag=s[s[k].ch[0]].has_tag|s[s[k].ch[1]].has_tag|(s[k].tg>0)|(s[k].tg_pt>0);}
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(var[j]>mx) 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];
// printf("node %d %d %d %d\n",k,p[mid][0],p[mid][1],p[mid].v);
// printf("%d %d %d\n",k,s[k].ch[0],s[k].ch[1]);
for(int j=0;j<K;j++){
if(s[k].ch[0]) chkmin(s[k].mn[j],s[s[k].ch[0]].mn[j]),chkmax(s[k].mx[j],s[s[k].ch[0]].mx[j]);
if(s[k].ch[1]) chkmin(s[k].mn[j],s[s[k].ch[1]].mn[j]),chkmax(s[k].mx[j],s[s[k].ch[1]].mx[j]);
} pushup0(k);
}
struct blk_ds{
ll blk_sum[BLK+5],val[MAXN+5];
int blk_cnt,blk_sz,bel[MAXN+5],L[BLK+5],R[BLK+5];
void init(){
blk_sz=(int)sqrt(m);blk_cnt=(m-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,m);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
}
void add(int x,ll v){/*printf("add %d %lld\n",x,v);*/blk_sum[bel[x]]+=v;val[x]+=v;}
ll query(int l,int r){
if(bel[l]==bel[r]){
ll sum=0;
for(int i=l;i<=r;i++) sum+=val[i];
return sum;
} else {
ll sum=0;
for(int i=l;i<=R[bel[l]];i++) sum+=val[i];
for(int i=bel[l]+1;i<bel[r];i++) sum+=blk_sum[i];
for(int i=L[bel[r]];i<=r;i++) sum+=val[i];
return sum;
}
}
} B;
struct bar{int x1,y1,x2,y2;} b[MAXN+5];
vector<pii> qv[MAXN+5];
ll res[MAXQ+5];
bool dfscheck(int k);
void clrtag(int k){
if(!s[k].has_tag||!k) return;
if(s[k].tg) B.add(s[k].tg,-s[k].sum),s[k].tg=0;
if(s[k].tg_pt) B.add(s[k].tg_pt,-s[k].val.v),s[k].tg_pt=0;
clrtag(s[k].ch[0]);clrtag(s[k].ch[1]);s[k].has_tag=0;
}
void pushdown(int k){
if(s[k].tg){
if(s[k].ch[0]) s[s[k].ch[0]].tg=s[k].tg;
if(s[k].ch[1]) s[s[k].ch[1]].tg=s[k].tg;
s[k].tg_pt=s[k].tg;s[k].tg=0;
s[s[k].ch[0]].has_tag=s[s[k].ch[1]].has_tag=1;
}
}
//bool dfscheck(int k){
// if(!k) return 0;
// bool ok=dfscheck(s[k].ch[0])|dfscheck(s[k].ch[1]);
// if(ok&&s[k].tg) exit(1);
// return ok|(s[k].tg>0)|(s[k].tg_pt>0);
//}
void pushtag(int k,int x1,int y1,int x2,int y2,int v){
if(!k) return;
if(s[k].mx[0]<x1||s[k].mn[0]>x2||s[k].mx[1]<y1||s[k].mn[1]>y2) return;
pushdown(k);
if(x1<=s[k].mn[0]&&s[k].mx[0]<=x2&&y1<=s[k].mn[1]&&s[k].mx[1]<=y2){
clrtag(k);B.add(v,s[k].sum);s[k].tg=v;pushup(k);return;
}
if(x1<=s[k].val[0]&&s[k].val[0]<=x2&&y1<=s[k].val[1]&&s[k].val[1]<=y2){
if(s[k].tg_pt) /*printf("!!! %d ",s[k].val[0]),*/B.add(s[k].tg_pt,-s[k].val.v);
s[k].tg_pt=v;/*printf("!!! %d ",s[k].val[0]);*/B.add(s[k].tg_pt,s[k].val.v);
} pushtag(s[k].ch[0],x1,y1,x2,y2,v);pushtag(s[k].ch[1],x1,y1,x2,y2,v);
pushup(k);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&p[i][1],&p[i].v),p[i][0]=i;
scanf("%d",&m);for(int i=1;i<=m;i++) scanf("%d%d%d%d",&b[i].x1,&b[i].x2,&b[i].y1,&b[i].y2);//pay attention to the sequence of input
scanf("%d",&qu);for(int i=1,l,r;i<=qu;i++) scanf("%d%d",&l,&r),qv[r].pb(mp(l,i));
build(rt,1,n);B.init();
for(int i=1;i<=m;i++){
pushtag(rt,b[i].x1,b[i].y1,b[i].x2,b[i].y2,i);
for(pii p:qv[i]) res[p.se]=B.query(p.fi,i);
// dfscheck(rt);
}
for(int i=1;i<=qu;i++) printf("%lld\n",res[i]);
return 0;
}

欸,貌似再下一个题号就是我们月赛的题了呢

洛谷 P6783 - [Ynoi2008] rrusq(KDT+势能均摊+根号平衡)的更多相关文章

  1. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  2. bzoj5312: 冒险(势能均摊线段树)

    题目链接 BZOJ5312: 冒险 题解 如果一次操作对区间& 和 区间| 产生的影响是相同的,那么该操作对整个区间的影响都是相同的 对于每次操作,在某些位上的值,对于整个区间影响是相同的,对 ...

  3. 洛谷 P6349 - [PA2011]Kangaroos(KDT+标记下放)

    洛谷题面传送门 KDT 上打标记的 hot tea. 考虑将询问 \(A,B\) 看作二维平面直角坐标系上的一个点 \((A,B)\),那么我们这样考虑,我们从左到右扫过全部 \(n\) 个区间并开一 ...

  4. 洛谷P4891 序列(势能线段树)

    洛谷题目传送门 闲话 考场上一眼看出这是个毒瘤线段树准备杠题,发现实在太难调了,被各路神犇虐哭qwq 考后看到各种优雅的暴力AC......宝宝心里苦qwq 思路分析 题面里面是一堆乱七八糟的限制和性 ...

  5. 洛谷P1337 【[JSOI2004]平衡点 / 吊打XXX】(模拟退火)

    洛谷题目传送门 很可惜,充满Mo力的Mo拟退火并不是正解.不过这是一道最适合开始入手Mo拟退火的好题. 对模拟退火还不是很清楚的可以看一下 这道题还真和能量有点关系.达到平衡稳态的时候,物体的总能量应 ...

  6. 洛谷P1198 [JSOI2008]最大数

    P1198 [JSOI2008]最大数 267通过 1.2K提交 题目提供者该用户不存在 标签线段树各省省选 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 WA80的戳这QwQ BZOJ都 ...

  7. 关于三目运算符与if语句的效率与洛谷P2704题解

    题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最 ...

  8. 洛谷P1126 机器人搬重物

    洛谷1126 机器人搬重物 题目描述 机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格, ...

  9. 洛谷 P3384 【模板】树链剖分

    树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...

随机推荐

  1. OO电梯作业总结

    (一)第五次作业 一.设计思路 生产消费者模型,输入接口是producer,调度器是tray,电梯是customer.由于只有一架电梯,所以生产消费模型满足以下条件: 一个生产者,一个消费者 托盘不为 ...

  2. mongodb的索引操作

    在mongodb中,当我们一个集合中的数据量非常大时,比如几百万条数据,如果不使用索引,对数据的查询就会进行全表扫描,这个时候查询的速度就会非常的慢,此时我们就需要为集合建立上索引,从而加快查询的速度 ...

  3. MD支持程度测试

    Editor.md 目录 (Table of Contents) [TOCM] 目录 Editor.md Heading 1 Heading 2 Heading 3 Heading 4 Heading ...

  4. 到底能不能用 join

    互联网上一直流传着各大公司的 MySQL 军规,其中关于 join 的描述,有些公司不推荐使用 join,而有些公司则规定有条件的使用 join, 它们都是教条式的规定,也没有详细说其中的原因,这就很 ...

  5. 写一段java程序来执行linux命令

    摘要 在日常开发中,程序员需要经常查询服务器日志来排查问题和调试程序.如果是本地调试还好,但项目一旦发布到服务器上,每次查日志就很麻烦,而且日志量巨大,有时我们无法找到我们需要的信息.经常需要借助第三 ...

  6. linux shell 提示符

    当我们打开或者登陆到一个终端的时候都会显示一长串提示符 void@void-ThinkPad-E450:~$ 提示符一般包含当前登陆的用户名 ,主机名,以及当前工作路径路径,最后都是以 $ 或者 # ...

  7. Git 极速上手(超简单)

    前言:本文主要介绍了一种快速入门使用Git的方法,通过四步完成本地仓库构建和推送到远程仓库(Github.Gitee码云),简单说明最常用的命令,不需要明白Git的原理即可使用,本文不介绍具体原理. ...

  8. java+selenium+testNG+Allure报表【新增截图到报表功能】

    1.pom.xml配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://w ...

  9. 合并代码操作 | git fetch 与 git pull

    前言 首先我们要说简单说git的运行机制.git分为本地仓库和远程仓库,我们一般情况都是写完代码,commit到本地仓库(生成本地仓的commit ID,代表当前提交代码的版本号),然后push到远程 ...

  10. 使用 SSL 加密的 JDBC 连接 SAP HANA 数据库

    近期客户为满足安全要求,提了让业务应用使用 SSL 方式连接 SAP HANA 数据库的需求.本人查询 SAP官方文档 发现数据库支持 SSL 连接,有参数直接加到 JDBC 的 URL 后边就行了, ...