题意:

从左到右排列着\(n\)个多米诺骨牌,它们分别站在\(x\)轴上的位置\(p_i\)上且高度为\(l_i\)。

当第\(i\)个多米诺骨牌向右倒下时,如果\(p_i < p_j \leq p_i + l_i\)那么第\(j\)个多米诺骨牌也会倒下,以此类推。

然后有\(q\)个询问\([x, \, y]\),要推倒第\(x\)个多米诺骨牌,而且最终要使得第\(y\)个多米诺骨牌倒下。

为了使第\(y\)个倒下,可以加长某些牌的长度。

对于每个询问,求最少加长的总长度之和。

分析:

对于第\(i\)个牌,定义\(R_i\)为推倒第\(i\)个牌,所倒下的牌中\(p_j+l_j\)的最大值。

有递推式:\(R_i=max \{ p_i+l_i, \, max\{ R_j | p_i < p_j \leq p_i+l_i \} \}\)

\(R_i\)可以通过维护线段树计算得到。

接下来根据\(R_i\)计算\(U_i\),表示推倒第\(i\)个牌后,最左边没有倒下的牌的编号。

因此从\(x\)到\(U_x\),我们至少需要增加\(p_{U_{x}} - R_x\)的长度。

所以我们向右一步一步地加,直到第\(y\)块倒下为止。

但是这样每次查询的复杂度为\(O(n)\)的。

所以还需要二进制优化一下,类似于求\(LCA\)的倍增算法。

\(anc(i, \, j)\)表示迭代\(2^j\)次\(U_i\)最后得到的牌的编号,\(cost(i, \, j)\)表示相应增加的牌的长度。

\(O(nlogn)\)预处理一下,就可以做到\(O(logn)\)查询。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = 200000 + 10; int n, q;
int p[maxn], l[maxn];
int R[maxn], U[maxn]; int maxv[maxn << 2]; void update(int o, int L, int R, int p, int v) {
if(L == R) { maxv[o] = v; return; }
int M = (L + R) / 2;
if(p <= M) update(o<<1, L, M, p, v);
else update(o<<1|1, M+1, R, p, v);
maxv[o] = max(maxv[o<<1], maxv[o<<1|1]);
} int query(int o, int L, int R, int qL, int qR) {
if(qL <= L && R <= qR) { return maxv[o]; }
int M = (L + R) / 2;
int ans = 0;
if(qL <= M) ans = max(ans, query(o<<1, L, M, qL, qR));
if(qR > M) ans = max(ans, query(o<<1|1, M+1, R, qL, qR));
return ans;
} int anc[maxn][20], cost[maxn][20]; int lb(int l, int r, int x) {
while(l < r) {
int mid = (l + r) / 2 + 1;
if(p[mid] <= x) l = mid;
else r = mid - 1;
}
return l;
} int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d%d", p + i, l + i);
for(int i = n; i; i--) {
R[i] = p[i] + l[i];
int lft = i + 1;
int rgh = lb(1, n, p[i] + l[i]);
if(lft <= rgh) R[i] = max(R[i], query(1, 1, n, lft, rgh));
update(1, 1, n, i, R[i]);
}
for(int i = 1; i <= n; i++) {
U[i] = upper_bound(p + 1, p + 1 + n, R[i]) - p;
if(U[i] == n + 1) U[i]--;
} for(int i = 1; i <= n; i++) {
anc[i][0] = U[i];
cost[i][0] = max(0, p[U[i]] - R[i]);
}
for(int j = 1; (1 << j) < n; j++)
for(int i = 1; i <= n; i++) if(anc[i][j-1] != n) {
int t = anc[i][j-1];
anc[i][j] = anc[t][j-1];
cost[i][j] = cost[i][j-1] + cost[t][j-1];
} scanf("%d", &q);
while(q--) {
int x, y; scanf("%d%d", &x, &y);
int ans = 0;
for(int i = 19; i >= 0; i--) if(anc[x][i] && anc[x][i] <= y) {
ans += cost[x][i];
x = anc[x][i];
}
if(x < y) ans += max(0, p[y] - p[U[x]]);
printf("%d\n", ans);
} return 0;
}

CodeForces 500E New Year Domino的更多相关文章

  1. 【codeforces 500E】New Year Domino

    [题目链接]:http://codeforces.com/problemset/problem/500/E [题意] 有n个多米诺骨牌; 你知道它们的长度; 然后问你,如果把第i骨牌往后推倒,然后要求 ...

  2. Codeforces 238 div2 B. Domino Effect

    题目链接:http://codeforces.com/contest/405/problem/B 解题报告:一排n个的多米诺骨牌,规定,若从一边推的话多米诺骨牌会一直倒,但是如果从两个方向同时往中间推 ...

  3. 【CodeForces 353 A】Domino

    [链接] 我是链接,点我呀:) [题意] [题解] 分类讨论一波 设第一个数组的奇数个数为cnt1 第二个数组的奇数个数为cnt2 显然只有在(cnt1+cnt2)%2==0的情况下. 才可能第一个数 ...

  4. CF数据结构练习

    1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...

  5. Codeforces Good Bye 2015 C. New Year and Domino 前缀和

    C. New Year and Domino 题目连接: http://www.codeforces.com/contest/611/problem/C Description They say &q ...

  6. CodeForces - 50A Domino piling (贪心+递归)

    CodeForces - 50A Domino piling (贪心+递归) 题意分析 奇数*偶数=偶数,如果两个都为奇数,最小的奇数-1递归求解,知道两个数都为1,返回0. 代码 #include ...

  7. Codeforces 500 E. New Year Domino

    \(>Codeforces \space 500 E. New Year Domino<\) 题目大意 : 数轴上有序排列着 \(n\) 块多米诺骨牌, 第 \(i\) 块骨牌坐标为 \( ...

  8. Codeforces Round #609 (Div. 2) D. Domino for Young

    链接: https://codeforces.com/contest/1269/problem/D 题意: You are given a Young diagram. Given diagram i ...

  9. Codeforces Round #588 (Div. 2) C. Anadi and Domino(思维)

    链接: https://codeforces.com/contest/1230/problem/C 题意: Anadi has a set of dominoes. Every domino has ...

随机推荐

  1. winform代码生成器(一)

    (PS  sqlhelper的文件 竟放到 类库里了,第二篇已做了分离,边做边写的 ^_^) 做 Winform  项目时,要拖很多控件,感觉在做重复的事,那就应该用程序来完成,那就自己写一个吧.-- ...

  2. 关于dataTable 生成JSON 树

    背景: POSTGRESL + C#  + DHTMLX SUIT 一个表生成一个JSON串,这个不是很麻烦: 1.在数据库(postges)中:  json_agg(row_to_json(t)) ...

  3. ionic 2 起航 控件的使用 客户列表场景(四)

    接下来,我们的客户列表要怎么刷新数据呢? 我们不会安卓开发,不会ios开发,没关系,我们还有ionic 2.ionic 2的控件 Ion-refresher 轻松帮我们搞掂. <!--下拉刷新- ...

  4. 小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载五(使用PhoneGap获取设备信息)

    除了能够将HTML页面打包成可以直接安装运行的APP外,PhoneGap的一个最大优势在于可以通过JavaScript调用设备来访问设备上的硬件信息,从而实现一些原本只有依靠原生SDK才能够达到的目的 ...

  5. 备份和导入Outlook 2016 电子邮件签名

    在本文中,我将分享您在Outlook 2013和Outlook 2016中备份或导入签名的过程 在清除Outlook配置文件之前,请确保您通过在文件资源管理器中的配置文件中的APPDATA文件夹中复制 ...

  6. 用指针的方式实现,重写strrchr函数的功能

    char *strchrTest(char * ptr,char c); Action(){ char str[]={"thisisadog"}; char c='s'; lr_o ...

  7. python 之 re 模块

    re模块下的常用方法 1.findall:返回所有满足匹配条件的结果,放在列表里. import re # 查找数字 result = re.findall('\d+','nizhidao 123 w ...

  8. HDU 4734 F(x) (数位DP,基础)

    题意:  一个非负整数的十进制位是这样的 (AnAn-1An-2 ... A2A1),定义F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. ...

  9. 使用com.sun.imageio.plugins.png.PNGMetadata读取图片的元数据

    所谓图片元数据,就是除了我们肉眼看到的图片内容外,隐藏在这些内容背后的一些技术数据. 本文介绍如何使用Java代码将一张图片的隐藏信息读取出来. 首先不需要下载任何额外的Java库,用JDK自带的库就 ...

  10. Oracle RAC/Clusterware 多种心跳heartbeat机制介绍 RAC超时机制分析

    ORACLE RAC中最主要存在2种clusterware集群件心跳 &  RAC超时机制分析: 1.Network Heartbeat 网络心跳 每秒发生一次: 10.2.0.4以后网络心跳 ...