题面

题解

在网上看到有些做法,有什么平衡树、启发式合并等等总之复杂度O(Tnlog^2(n))的不优做法,这里我就用一个O(Tnlogn)的做法好了

其实大体上推导的思路都是一样的。

我们很容易发现,如果全选没水的条件,一定是一组满足条件的解。关键是我们要如何选择有水的条件。

容易发现,对于一个有水条件,它一定会使包含它的一段连续区间内高度小于它的地方都有水。而在其区间内,没有它高的有水条件,当它满足时,一定也能被满足,而没有它高的无水条件,当它满足时,一定不能被满足。

我们先考虑如何求出这一段区间。这一段区间内一定不包含比当前水位置高的墙……

之后对于这个区间,我们考虑如何维护在这个区间内灌水满足的条件……而选择这个条件可以带来的贡献,是其导致成立的有水条件减去导致不成立的无水条件。

我们求出了每个有水条件对应的区间与贡献后,可以通过dp来求出最大的满足条件值。


摘自 https://blog.csdn.net/tan_tan_tann/article/details/109788508 (有删改 )

我简单 解释 概括一下,

我们从结果方向考虑,最后灌完水了,肯定会是很多段连续的小水潭,彼此分隔开,而且其贡献就是每段水潭水下覆盖的“有水条件”数 + 水潭水面上方的“无水条件”数 + “岸上”的无水条件数。

而每段水潭的高度肯定恰好与某个有水条件的高度+1相等,因为若稍微高一些(不触碰到下一个有水条件)肯定不会更优,

因此,我们再从有水条件反过来想,容易发现对于每个有水条件,令其满足的“最低”水潭的覆盖区间是一定的,即上面摘录的“这一段区间内一定不包含比当前水位置高的墙”,事实上,由于水潭高度不会是整数,所以潭内的墙一定比水面低,潭两边的墙一定更高。那么我们把墙和有水条件按高度从大到小排序,把墙从高到矮往水箱中加(加进一个线段树中),同时,在大于某个有水条件高度的墙全部加进去后,把这个条件的左右区间确定了(即在线段树上查询原位置(i)左边最近的墙和右边最近的墙)。

把每个有水条件的区间确定后,我们再分别解决水面下和水面上的贡献。

水面下的贡献即为高度比水面矮、且原位置 i 在此区间内的有水条件数。类似地,我们把有水条件按高度从小到大排序,然后从头一个一个加进线段树内(原位置 i 的地方加 1),再查询此条件对应区间内的条件数量(这里可能有人会疑惑,高度相等的也要算,万一在他后面没算到怎么办?不用担心,做就是了,因为高度相等、区间重合的有水条件是等价的,在算最后一个这样等价的条件时会把所有贡献都计算进去)。

水面上的贡献即为无水条件的贡献嘛,类比一下,也这么处理就是了。

最后一步,我们设dp[i]为从左到右处理到 i 位置时最大的贡献(此dp默认没有影响到 i 后面的位置),把每个有水条件按照右端点挂到序列上,把每个位置的无水条件数处理出来,

dp[i] = max{dp[i-1] + (i 位置无水条件数) ,dp[L[j] - 1] + ans[j] (j 为 R[j] == i 的有水条件)}

总Answer = 最大的dp[i]

复杂度 O(Tnlogn)

CODE

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define ULL unsigned long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
#pragma GCC optimize(2)
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
int a[MAXN],b[MAXN];
int sm[MAXN],w[MAXN];
int dp[MAXN];
vector<int> col[MAXN];
struct qu{
int i,j,l,r;
}ex[MAXN],no[MAXN];
inline bool cm1(qu a,qu b) {return a.j > b.j;}
int cte,ctn;
struct it{
int id,h;
}hi[MAXN];
inline bool cmp(it a,it b) {return a.h > b.h;}
//------------------------------------------ZKW
int rr[MAXN<<2],ll[MAXN<<2],M;
void maketree(int n) {
M=1;while(M < n+2)M <<= 1;
for(int i=(M<<1|1);i>0;i--)rr[i]=n;
memset(ll,0,sizeof(ll));
}
void addr(int l,int r,int ad) {
int s = M + l - 1,t = M + r + 1;
while(s || t) {
if((s>>1) != (t>>1)) {
if(!(s & 1)) rr[s^1] = min(rr[s^1],ad);
if(t & 1) rr[t^1] = min(rr[t^1],ad);
}else break;
s >>= 1;t >>= 1;
}return ;
}
void addl(int l,int r,int ad) {
int s = M + l - 1,t = M + r + 1;
while(s || t) {
if((s>>1) != (t>>1)) {
if(!(s & 1)) ll[s^1] = max(ll[s^1],ad);
if(t & 1) ll[t^1] = max(ll[t^1],ad);
}else break;
s >>= 1;t >>= 1;
}return ;
}
void query(int x,int &l,int &r) {
int s = M + x;l = 0;r = 0x7f7f7f7f;
while(s) {l = max(l,ll[s]);r = min(r,rr[s]);s>>=1;}
return ;
}
//-----------------------------------ZKW_End
int c[MAXN];
void addtree(int x,int y) {while(x<=n)c[x] += y,x += lowbit(x);}
inline int sum(int x) {int as=0;while(x>0)as += c[x],x -= lowbit(x);return as;}
int main() {
// freopen("tank.in","r",stdin);
// freopen("tank.out","w",stdout);
int T = read();
while(T --) {
n = read();m = read();
b[0] = b[n] = 0x7f7f7f7f;
for(int i = 1;i < n;i ++) {
b[i] = read();
hi[i].id = i;hi[i].h = b[i];
}
for(int i = 1;i <= n;i ++) {
sm[i] = 0; col[i].clear();
}
bool flag = 1;
maketree(n);
cte = ctn = 0;
for(int i = 1;i <= m;i ++) {
s = read();o = read();k = read();
if(k == 1) {
ex[++ cte].i = s;
ex[cte].j = o;
}
else no[++ ctn].i = s,no[ctn].j = o,sm[s] ++;
}
sort(ex + 1,ex + 1 + cte,cm1);
sort(no + 1,no + 1 + ctn,cm1);
sort(hi + 1,hi + n,cmp);
int j = 1;
for(int i = 1;i < n;i ++) {
while(j <= cte && ex[j].j >= hi[i].h) {
query(ex[j].i,ex[j].l,ex[j].r);
ex[j].l ++;j ++;
}
addr(1,hi[i].id,hi[i].id);
addl(hi[i].id+1,n,hi[i].id);
}
while(j <= cte) {query(ex[j].i,ex[j].l,ex[j].r);ex[j].l ++;j ++;}
j = 1;
memset(c,0,sizeof(c));
for(int i = 1;i <= cte;i ++) {
while(j <= ctn && no[j].j > ex[i].j)
addtree(no[j].i,1),j ++;
w[i] = sum(ex[i].r) - sum(ex[i].l-1);
}
memset(c,0,sizeof(c));
for(int i = cte;i > 0;i --) {
addtree(ex[i].i,1);
col[ex[i].r].push_back(i);
w[i] += sum(ex[i].r) - sum(ex[i].l-1);
}
memset(dp,0,sizeof(dp));
int ans = 0;
for(int i = 1;i <= n;i ++) {
dp[i] = dp[i-1] + sm[i];
for(int j = 0;j < (int)col[i].size();j ++) {
int l = ex[col[i][j]].l;
int wi = w[col[i][j]];
dp[i] = max(dp[i],dp[l-1] + wi);
}
ans = max(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}

「雅礼集训 2017 Day2」水箱 (数据结构+dp ,一个log)的更多相关文章

  1. loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移

    $ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...

  2. loj#6032. 「雅礼集训 2017 Day2」水箱(并查集 贪心 扫描线)

    题意 链接 Sol 神仙题+神仙做法%%%%%%%% 我再来复述一遍.. 首先按照\(y\)坐标排序,然后维护一个扫描线从低处往高处考虑. 一个连通块的内状态使用两个变量即可维护\(ans\)表示联通 ...

  3. LOJ#6032. 「雅礼集训 2017 Day2」水箱

    传送门 首先可以有一个平方复杂度的 \(DP\) 设 \(f_{i,j}\) 表示前面 \(i\) 个小格,高度为 \(j\) 的最大答案 令 \(h_i\) 表示隔板 \(i\) 的高度 当 \(j ...

  4. 「雅礼集训 2017 Day2」水箱

    题目链接 题意分析 我们用\(f[i][j]\)表示当前到达第\(i\)个位置水位高度为\(j\)的答案 如果那么\(h[i]\)为\(i\)和\(i+1\)之间的支柱高度 那么如果\(j≤h[i]\ ...

  5. 「雅礼集训 2017 Day2」解题报告

    「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...

  6. #6034. 「雅礼集训 2017 Day2」线段游戏 李超树

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...

  7. 【loj6034】「雅礼集训 2017 Day2」线段游戏

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:Special Judge 上传者: 匿名 题目描述 ...

  8. loj#6033. 「雅礼集训 2017 Day2」棋盘游戏(二分图博弈)

    题意 链接 Sol 第一次做在二分图上博弈的题..感觉思路真是清奇.. 首先将图黑白染色. 对于某个点,若它一定在最大匹配上,那么Bob必胜.因为Bob可以一直沿着匹配边都,Alice只能走非匹配边. ...

  9. [LOJ#6033]. 「雅礼集训 2017 Day2」棋盘游戏[二分图博弈、匈牙利算法]

    题意 题目链接 分析 二分图博弈经典模型,首先将棋盘二分图染色. 考虑在某个最大匹配中: 如果存在完美匹配则先手必败,因为先手选定的任何一个起点都在完美匹配中,而后手则只需要走这个点的匹配点,然后先手 ...

随机推荐

  1. 总结 到 GDOI 2021 这个阶段

    截止本蒟蒻第一次体验省选(虽然是普及组) 本蒟蒻已经有了许多收获,却也有很多不足 优点 对一些学过的知识掌握还行 没了 缺点 会却做不出来 有一些题不难,却想不到正解 如 Day2 T1 ,就是移一下 ...

  2. .NET中获取Windows的常见路径

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年6月30日. 一.说明 每种平台都其预定义的规则,比如Windows平台有自己的规定.公司也有预定义的规章制度.那么在平台上开发和干活 ...

  3. VMware Workstation 虚拟机详细安装教程

    一.介绍篇 VMware Workstation 16 Pro是VMware(威睿公司)于2021年最新发布的一代虚拟机软件,软件的中文名是"VMware 工作站 16 专业版". ...

  4. 1.2 操作系统的第二个功能——并发功能 -《zobolの操作系统学习札记》

    1.2 操作系统的第二个功能--并发功能 目录 1.2 操作系统的第二个功能--并发功能 问1:什么是并发功能?并发功能是必要的吗? 问2:并发功能必须要求拥有多核CPU吗? 问3:多核CPU和单核C ...

  5. JS:函数

    Function:函数 1. 定义一个函数:function functionname(argument) { 代码块 return }: 调用此函数:fn() 2.函数是定义了一种方法,只有被调用才 ...

  6. Python自动化办公:将文本文档内容批量分类导入Excel表格

    序言 (https://jq.qq.com/?_wv=1027&k=GmeRhIX0) 它来了,它又来了. 本文实现用Python将文本文件自动保存到Excel表格里面去. 需求 将锦江区.t ...

  7. Nacos配置失败(java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance after all server)

    解决: nacos服务器过载,可以删掉nacos文件夹下的data文件夹,重新启动.

  8. Unsupported major.minor version 52.0 (unable to load class org.apache.kafka.clients.producer.Produce异常解决方法

    在控制台输入java -version,查看自己的版本是多少,我的查出来是1.8的.随后将服务器上的改为1.8的就可以了.

  9. Day05 表格

    表格 <table width="300" border="1" cellspacing="0"> <caption> ...

  10. PoweJob高级特性-MapReduce完整示例

    由于网上搜索 PowerJob MapReduce 都是设计原理,demo也展示个空壳子,没有演示Map到Reduce结果怎么传递,对于没有MR开发经验的人来说并没有什么帮助,所以这里写了一个有完整计 ...