原文链接 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. Python002-操作MSSQL(Microsoft sql server)基础示例(二)

    前文http://www.cnblogs.com/fengpingfan/p/7675291.html,讲述了python操作mssql的步骤.环境创建.常用方法等,本文将实例演示python操作ms ...

  2. docker制作tomcat镜像

    准备cestos镜像.tomcat.jdk cestos是docker pull下来的 在/opt/下创建docker:mkdir -p /opt/docker 把tomcat和jdk解压到docke ...

  3. 使用Eclipse来操作HDFS的文件

    一.常用类 1.Configuration Hadoop配置文件的管理类,该类的对象封装了客户端或者服务器的配置(配置集群时,所有的xml文件根节点都是configuration) 创建一个Confi ...

  4. python利用requests库模拟post请求时json的使用

    我们都见识过requests库在静态网页的爬取上展现的威力,我们日常见得最多的为get和post请求,他们最大的区别在于安全性上: 1.GET是通过URL方式请求,可以直接看到,明文传输. 2.POS ...

  5. 微信小程序封装年月日时分组件

    第一步,在page下新建component文件,放你封装的小组件,和vue里的component差不多 第二步,在需要使用的组件的.json文件中添加usingComponents 第三步,在页面中引 ...

  6. Summary: Calculate average where sum exceed double limits

    What is a good solution for calculating an average where the sum of all values exceeds a double's li ...

  7. python小程序--Two

    一.程序需求 1.启动程序后,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 4.可随时退出,退出时,打印已购买商品和 ...

  8. 主线程 RunLoop 学习笔记

    以下为主RunLoop 的输出,能够看到不同的source0,source1,observer ---------------------------------- CFRunLoop{wakeup ...

  9. vue命令行错误处理

    全局安装vue/cli时:npm install -g @vue/cli (1)Error: EACCES: permission denied, access '/usr/local/lib/nod ...

  10. (转)利用CAS算法实现通用线程安全状态机

    在多线程环境下,如果某个类是有状态的,那我们在使用前,需要保证所有该类的实例对象状态一致,否则会出现意向不到的bug.下面是通用线程安全状态机的实现方法. public class ThreadSav ...