原文链接 https://www.cnblogs.com/cly-none/p/CERC2017B.html

题意:在一个网格平面上,有\(n\)个点,其中第\(i\)个点在以\((x_i, y_i)\)为右上角的网格中。有\(m\)次操作,每次给出一个点\((x,y)\),表示从\((x,y)\)开始,向左和向下画线直到与之前画的线或坐标轴相交。这样会划分出以\((x,y)\)为右上角的新区域。你需要对每次操作求出,新区域中点的数量。

$n , m \leq 3 \times 10^5, \ 1 \leq x_i, y_i \leq 10^9, $ 每次操作的 \(x\) 和 \(y\) 分别互不相同。

首先,我们容易得出各种\(O(n \log ^ 2n)\)的数据结构做法。然而,它们并没有太大的启发意义。

考虑离线下来,处理每个点对所有操作的贡献。

考虑求出每个点和操作最后是被哪个操作控制的。也就是能直接覆盖这个点(或操作)的操作中时间最早的。这样会形成森林的结构。显然,一个点只会对它的祖先产生贡献。而它对某个祖先\(v\)产生贡献的冲要条件就是在它到\(v\)的路径上没有比\(v\)更早的操作。

求这个森林可以使用扫描线。按\(y\)从上往下扫描,每加入一个操作就删去在它前面的出现时间晚于它的操作。这可以用set来维护。

剩下的部分可以按时间从前往后枚举所有操作,每次答案就是它的子树和,然后切断它与父亲的边。方便起见,可以用时间倒流的技巧,就相当与每次合并一个点和它的父亲。用并查集维护即可。

时间复杂度\(O(n \log n)\)。

#include <bits/stdc++.h>
using namespace std;
#define gc() getchar()
template <typename tp>
inline void read(tp& x) {
x = 0; char tmp; bool key = 0;
for (tmp = gc() ; !isdigit(tmp) ; tmp = gc())
key = (tmp == '-');
for ( ; isdigit(tmp) ; tmp = gc())
x = (x << 3) + (x << 1) + (tmp ^ '0');
if (key) x = -x;
}
const int N = 300010, INF = 0x3f3f3f3f;
struct edge {
int la,b;
} con[N << 1];
int tot,fir[N << 1];
void add(int from,int to) {
con[++tot] = (edge) {fir[from],to};
fir[from] = tot;
}
struct data {
int x,y,v;
bool operator < (const data& a) const {
return y > a.y;
}
} dat[N << 1];
int n,m,cnt,fa[N],val[N],uni[N],ans[N];
int getfa(int pos) {
return pos == uni[pos] ? pos : uni[pos] = getfa(uni[pos]);
}
typedef pair<int,int> pii;
set<pii> st;
set<pii> :: iterator t, t1;
void ins(int x,int y) {
t = st.insert(pii(x,y)).first;
while (t != st.begin()) {
t1 = t;
-- t1;
if (t1 -> second < y) break;
st.erase(t1);
}
}
int ask(int p) {
return st.upper_bound(pii(p+1,0))->second;
}
int main() {
read(n);
for (int i = 1, x, y ; i <= n ; ++ i) {
read(x), read(y);
-- x, -- y;
dat[++cnt] = (data) {x,y,0};
}
read(m);
for (int i = 1, x, y ; i <= m ; ++ i) {
read(x), read(y);
dat[++cnt] = (data) {x,y,i};
}
dat[++cnt] = (data) {INF,INF,m+1};
sort(dat+1,dat+cnt+1);
for (int i = 1, las = 1, tmp ; i <= cnt ; ++ i) {
if (dat[i].y != dat[las].y) {
for (int j = las ; j < i ; ++ j)
if (dat[j].v) ins(dat[j].x, dat[j].v);
las = i;
}
tmp = ask(dat[i].x);
if (dat[i].v) fa[dat[i].v] = tmp;
else ++ val[tmp];
}
for (int i = 1 ; i <= m ; ++ i)
uni[i] = i;
for (int i = m ; i >= 1 ; -- i) {
ans[i] = val[getfa(i)];
uni[getfa(i)] = getfa(fa[i]);
val[getfa(fa[i])] += ans[i];
}
for (int i = 1 ; i <= m ; ++ i)
printf("%d\n",ans[i]);
return 0;
}

小结:这是一道技巧性比较强的数据结构题。利用询问间的关系解题的思路,还是有启发意义的。

【做题】CERC2017B. Buffalo Barricades——时间倒流的更多相关文章

  1. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  2. ACM 做题过程中的一些小技巧。

    ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...

  3. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

  4. SDOI2014 R1做题笔记

    SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(

  5. SDOI2016 R1做题笔记

    SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...

  6. 【做题】spoj4060 A game with probability——dp

    赛前做题时忽然发现自己概率博弈类dp很弱,心好慌.(获胜概率或最优解期望) 于是就做了这道题,续了特别久. 一开始列dp式子的时候就花了很长时间,首先搞错了两次,然后忘记了根据上一轮dp值直接确定选什 ...

  7. noip做题记录+挑战一句话题解?

    因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...

  8. 小学生轻松做题App

    作业链接:https://edu.cnblogs.com/campus/fzzcxy/2016SE/homework/2180 原型模型设计工具:墨刀 原型模型链接:https://modao.cc/ ...

  9. BZOJ做题记录[0512~?]

    觉得做一道开一篇真不好...好多想找的东西都被刷下去了... 至于?的日期究竟到什么时候...还是看心情...但是估计不会超过七天吧 最后更新时间:05/19 10:42 [05/14 10:56]我 ...

随机推荐

  1. docker镜像导入导出

    1.使用 save命令将 镜像保存为文件docker save -o  自定义文件名.tar  已存在的镜像名 2.使用load命令将镜像文件保存到本地仓库docker load -i 自定义文件名. ...

  2. Oracle数据泵远程导入数据

    查看现存镜像目录 select * from dba_directories; 创建镜像目录 create or replace directory my_dir as 'local_dir' ; 把 ...

  3. npm手册

    npm现在都是随同NodeJS一起安装的包管理和分发工具,所以npm的安装,只要下载新版的nodejs已经集成了npm. 安装好了以后,直接输入npm或者npm help,会出来一些npm自带的命令. ...

  4. SQLServer无法打开用户默认数据库 登录失败错误4064的解决方法

    无法打开用户默认数据库,登录失败,其原因是登录帐户的默认数据库被删除. 解决办法是使用管理员帐户修改此登录帐户的默认数据库. 1.使用管理员帐号登入企业管理器,在“对象资源管理器”中,展开“安全性”— ...

  5. ASP.NET gridview导出excel,防止繁体产生有乱码的方式

    //1.先引用比如 : using System; using System.Collections.Generic; using System.Linq; using System.Web; usi ...

  6. 打造RecyclerView的n级列表

    先上效果图: 1.该多级列表的优势: 支持无限级列表展开 基于一个recyclerView实现 可以自定义每一级item的样式,定制化更强 2.设计的思路 数据结构List,ItemBean类中有变量 ...

  7. 微信扫描二维码安卓弹出默认浏览器(苹果打开App Store)打开下载链接

    使用微信推广的用户经常都会遇到推广链接被拦截导致无法下载app的情况,此时用户在微信中打开会提示“ 已停止访问该网页 ”.这对于使用微信营销的商家来说就很不友好且损失非常大,因为用户是不知道为什么打不 ...

  8. DDL、DML和DCL的区别与理解

    DML.DDL.DCL区别 . 总体解释: DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令 ...

  9. java第三次上机

    import java.util.*; class student{ String name; char sex; int age; String number; double score[]=new ...

  10. 关于富文本编辑器—UEditor(java版)的使用,以及如何将UEditor的文件/图片上传路径改成绝对路径

    突然发现好久没写博客了,感觉变懒了,是要让自己养成经常写文章的习惯才行.既可以分享自己的所学,和所想,和大家一起讨论,发现自己的不足的问题. 大家可能经常会用到富文本编辑器,今天我要说的是UEdito ...