题意:

从左到右排列着\(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. 获取jqGrid中选择的行的数据

    下面可以获取选择一行的id,如果你选择多行,那下面的id是最后选择的行的id: var id=$(‘#gridTable’).jqGrid(‘getGridParam’,'selrow’); 如果想要 ...

  2. HBuilder配置sass

    参考: https://www.cnblogs.com/padding1015/p/7133811.html 如果期间报错,参考步骤7,然后再重新安装配置 预编译配置--no-cache %FileN ...

  3. web标准、可用性、可访问性

    前言:大家不难发现,只要是招聘UED相关的岗位,如前端开发工程师.交互设计师.用户研究员甚至视觉设计师,一般都对web标准.可用性和可访问性的理解有要求.那么到底什么是web标准.可用性.可访问性呢? ...

  4. 配置文件无法修改(以修改my-default.ini为例)

    现象: 保存my-default.ini时如果提示“拒绝访问”,右击my-default.ini文件 解决办法: 属性—>安全—>修改权限

  5. 洛谷——普及练习场 普及组选手可冲刺训练,提高组选手亦可在此巩固基础。(Loading...)

    简单的模拟 关卡2-1,6 道题 开始普及组的训练!所谓模拟,就是直接根据题意编写,思维难度简单. //T1 铺地毯 #include <cstdio> #define N 10005 i ...

  6. java HashMap 内存泄漏

    import java.util.HashMap; import java.util.Map; public class HashMapOver { public static void main(S ...

  7. ps基础实例

    一:合并多个图片 1.先新件一个图片)CTRL+N),大小定成你想要的大小 2.把你要放入的照片用PS打开 3.把放入的照片用移动工具(V)拉到新件的图片里面 4.用CTRL+T调整大小(按住SHIF ...

  8. C#数组排序方法

    在C#中常用的数组排序的方法有:选择排序法.冒泡排序法.插入排序法和希尔排序法等. 一.选择排序法 using System;using System.Collections.Generic;usin ...

  9. 01_5_Struts_ActionMethod_DMI_动态方法调用

    01_5_Struts_ActionMethod_DMI_动态方法调用 1. ActionMethod_DMI_动态方法调用 Action执行的时候并不一定要执行execute()方法 可以在配置文件 ...

  10. Diff Two Arrays-freecodecamp算法题目

    Diff Two Arrays(比较两个数组) 1.要求 比较两个数组,然后返回一个新数组 该数组的元素为两个给定数组中所有独有的数组元素.换言之,返回两个数组的差异. 2.思路 定义一个新数组变量, ...