题目连接
题意:
给你一个长为n,宽为1,高为无穷的水缸。里面有n-1个高度不一的隔板隔开为1x1大小的区域。里面的水遵循物理定理。给你m次查询和回应,每个查询<x,y,z>。代表查询第x个区域高度为y+0.5的地方,如果z为0,回应为这个位置没有水,如果为z为1,则回应是有水。问:这些回应最多有多少个正确的。
题解:
从这个题就能清楚的看到人与人之间的差距。有的大佬用prioriaty_queue,50line直接通过。有的人用可并堆80line直接通过。有的人用线段树合并,接近200line,wa了10+发后贴着时限通过。

理论上线段树合并应该比prioriaty_queue快才对。一个O(nlogn)O(nlogn)O(nlogn),一个O(nlog2n)O(nlog^2n)O(nlog2n)。实则不是这样。因为我是个憨憨。一个线段树合并都能写出n^2的常数。

首先考虑没有水,那么符合要求的数量即为z=0的数量。对于一次查询。从这个查询区间开始,向右和向左找到第一个大于这次查询高度的隔板。那个这个区间段,就是水位正好处在该次查询是的占有区间段。我们发现一个事实。如果我们把水位从低到高枚举,每个出现过区间段,只会被合并到一个更大的区间段里,不会被再次拆分了。
所以憨憨的我开始了线段树合并。。。首先我们从低到高枚举水位,然后考虑这个合并区间段,然后看一看该区间原先的最好情况,和现在的最好情况的大小。现在的最好情况就是该区间段的所有比这次查询低或相等的1的数量,以及比这次查询高的0的数量之和。如果比原来的情况大。我们的答案就+=现在的情况-原来的情况。因为我们将原来的情况替换为现在的情况。最后就得出答案了。这里使用并查集维护每个区间段的l, r节点以及该区间段的最好情况。用线段树合并维护该区间段的每个高度的1,0数量。

下面是ac代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <bitset>
#include <array>
#include <cctype>
#include <time.h>#pragma GCC optimize(2)void read_f() { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); }
void fast_cin() { std::ios::sync_with_stdio(false); std::cin.tie(); }
void run_time() { std::cout << "ESC in : " << clock() * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl; }
template <typename T>
bool bacmp(const T & a, const T & b) { return a > b; }
template <typename T>
bool pecmp(const T & a, const T & b) { return a < b; }#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr(x, y) (make_pair((x), (y)))
#define pb(x) push_back(x);
using namespace std;const int N = 2e5 + 5;
const int Z = 3e5 + 5;int tot;
struct Node
{int l, r;int val1, val0;
}tr[N * 40];
int cnt, top;
int rt[N], bac[N*40]; // rt数组记录每个线段树的根节点
inline int newnod() { return cnt ? bac[cnt--] : ++tot; } // 开点操作
inline void del(int p) { bac[++cnt] = p; tr[p].l = tr[p].r = tr[p].val0 = tr[p].val1 = 0; } // 垃圾回收
inline void pushup(int p)
{tr[p].val0 = tr[tr[p].l].val0 + tr[tr[p].r].val0;tr[p].val1 = tr[tr[p].l].val1 + tr[tr[p].r].val1;
}
void insert(int &p, int pos, int v, int flag, int l = 1, int r = Z)
{//cout << pos <<endl;//cout << l << " " << r << endl;if (!p) p = newnod();if (l == r){if (flag == 1)tr[p].val1 += v;else tr[p].val0 += v;return;}int mid = (l + r) >> 1;//cout << pos << " " << mid << endl;if (pos <= mid) insert(tr[p].l, pos, v, flag, l, mid);else insert(tr[p].r, pos, v, flag, mid + 1, r);pushup(p);
}
int merge(int x, int y, int l = 1, int r = Z)
{if (!x || !y) return x + y;int mid = (l + r) >> 1;if (l == r){tr[x].val0 += tr[y].val0;tr[x].val1 += tr[y].val1;}else{tr[x].l = merge(tr[x].l, tr[y].l, l, mid);tr[x].r = merge(tr[x].r, tr[y].r, mid + 1, r);pushup(x);}del(y);return x;
}
int ask(int p, int l, int r, int cl, int cr, int flag)
{if (p == 0) return 0;if(cl <= l && r <= cr){if (flag == 0) return tr[p].val0;return tr[p].val1;}int mid = (l + r) >> 1;int val = 0;if (cl <= mid) val += ask(tr[p].l, l, mid, cl, cr, flag);if (cr > mid) val += ask(tr[p].r, mid+1, r, cl, cr, flag);return val;
}
int fa[N];
int fi(int x)
{if (fa[x] == x) return x;return fa[x] = fi(fa[x]);
}
pair<int, int> sg[N];
int good[N];
int su[N];
struct Q
{int x, y, z;
} q[N];
bool cmp(const Q &a, const Q &b)
{return a.y < b.y;
}
int lisan[N * 3], lcnt;
int getn(int x)
{return lower_bound(lisan+1, lisan+lcnt, x) - lisan;
}
int main()
{int t; cin >> t;int t0 = 1;while(t--){tot = cnt = 0;lcnt = 0;int n, m; scanf("%d%d", &n, &m);for (int i = 0; i <= n * 40; i++)tr[i].l = tr[i].r = tr[i].val0 = tr[i].val1 = 0;for (int i = 0; i <= n; i++)fa[i] = i, sg[i].first = sg[i].second = i, rt[i] = 0, good[i] =0;for (int i = 1; i< n; i++)scanf("%d", &su[i]), lisan[++lcnt] = su[i];int ans = 0;for (int i = 1; i <= m; i++){scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].z);lisan[++lcnt] = q[i].y;if (q[i].z == 0)good[q[i].x]++, ans++;}sort(lisan+1, lisan+lcnt+1);lcnt = unique(lisan+1, lisan+lcnt+1) - lisan;for (int i = 1; i <= m; i++)insert(rt[q[i].x], getn(q[i].y), 1, q[i].z);sort(q+1,q+m+1, cmp);for (int i = 1; i <= m; i++){if (q[i].z == 0) continue;int _rt = fi(q[i].x);int _l = sg[_rt].first, _r = sg[_rt].second;int res = good[_rt];while(sg[_rt].first - 1 >= 1 && su[sg[_rt].first - 1] <= q[i].y){int _x = fi(sg[_rt].first-1);rt[_rt] = merge(rt[_rt], rt[_x]);fa[_x] = _rt;sg[_rt].first = sg[_x].first;res += good[_x];good[_rt] += good[_x];}while(sg[_rt].second < n && su[sg[_rt].second] <= q[i].y){int _x = fi(sg[_rt].second+1);rt[_rt] = merge(rt[_rt], rt[_x]);fa[_x] = _rt;sg[_rt].second = sg[_x].second;res += good[_x];good[_rt] += good[_x];}int nres = ask(rt[_rt], 1, Z, getn(q[i].y)+1, Z, 0) + ask(rt[_rt], 1, Z, 1, getn(q[i].y), 1);ask(rt[_rt], 1, Z, 1, getn(q[i].y), 1);if (nres > good[_rt]){ans += nres - good[_rt];good[_rt] = nres;}// cout << ans <<endl;}printf("Case #%d: %d\n",t0++,  ans);}return 0;
}

线段树合并(HDU-5575 Discover Water Tank)相关推荐

  1. hdu 5575 Discover Water Tank(可合并堆)

    题目链接:hdu 5575 Discover Water Tank 题意: 有一个大水箱,里面有N-1个隔板,将这个大水箱分成了N个小水箱,每个隔板有一定的高度. 现在有m条信息,每条信息表示第x个水 ...

  2. HDU 5575 Discover Water Tank(线段树+自底向上dp+并查集)

    题意 给定n个挡板和m次回答,每次回答为x号水池的H+0.5高度是否有水,问这些回答互不矛盾的最大集合. 题解 设定状态dp[i][0-1]代表第i个区间枚举到当前回答后有水的最大不矛盾集合和没水的最 ...

  3. hdu 5575 Discover Water Tank 左偏树

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5575 题意: 现在有一个巨大的水库(可视为二维的),水库中间被 n−1n-1n−1 个挡板分成了 n ...

  4. HDU 5575 Discover Water Tank(左偏树)

    https://vjudge.net/problem/HDU-5575 题意: 有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同.现在有m次探测,每次探测在第x部分的y+0.5高度处是否有 ...

  5. HDU 5575 Discover Water Tank 并查集+左偏树

    不妨假定初始答案为所有的无水询问,因为这样一定没有冲突. 然后枚举有水询问.水位线到这里时,答案能否更优. 若水位线达到某一高度,则可能淹没旁边的水箱,那么实际就变成了一个大水箱,所以考虑用并查集来优 ...

  6. HDU 5575 Discover Water Tank

    原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5575 把每个水箱当作一个并查集,每个无水的探测当做一个左偏树.有水的探测则放在数组中.并用一个数组使水 ...

  7. HDU 5575 Discover Water Tank 并查集 树形DP

    题意: 有一个水槽,边界的两块板是无穷高的,中间有n-1块隔板(有高度),现有一些条件(i,y,k),表示从左到右数的第i列中,在高度为(y+0.5)的地方是否有水(有水:k = 1),问最多能同时满 ...

  8. 树形DP+并查集+左偏树, HDU-5575,Discover Water Tank,2015上海现场赛D题

    只是ACM/IICPC 2015 上海区域赛的一道题.原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5575 题目描述 N-1个木板把一个水箱划分成了N ...

  9. HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)

    题目大意: 有一个1维的长度为N,高度无限的水柜,现在要用N-1个挡板将其分为N个长度为1的小格,然后向水柜中注水,水可以低于挡板也可以以溢出去(这样就要与旁边格子的水位相同),现在有M次探测,探测i ...

最新文章

  1. java web代码规范:
  2. 万师傅使用云产品,上手简单、开箱即用、省去运维烦恼
  3. linux 笔记本键盘灯驱动程序,安装和使用CKB Next在Linux上更改Corsair键盘背光设置...
  4. 解决Ssh/Scp报错:Someone Could Be Eavesdropping On You Right Now (Man-In-The-Middle Attack)!
  5. 谜题39:您好,再见!
  6. 【原创】修复ios输入框获取焦点时不支持fixed的bug
  7. 数据bag中的激光雷达数据和相机数据分割出来
  8. php简单登陆,PHP简单实现单点登录
  9. Node.js 下载安装教程
  10. linux局域网连接网络打印机驱动程序,EBS on linux 网络打印机配置
  11. 深耕企业组网 H3C企业主网交换机评测
  12. cogs——1008. 贪婪大陆(清华巨佬代码)——树状数组
  13. TCP和Socket关系
  14. 环信第三方集成 -- 移动客服
  15. c编程----段定义的使用
  16. Vertica常用语法
  17. 学会提问的BERT:端到端地从篇章中构建问答对
  18. 基于爬虫爬取的数据,完成数据展示网站
  19. asp.net小说网站案例
  20. 排序二叉树的创建,插入和查找

热门文章

  1. SU2 _斯坦福大学的开源CFD代码
  2. translate-shell的使用方法
  3. Vishay 5 瓦表面贴装电阻器
  4. mfc中添加checkbox check、uncheck事件
  5. 你知道在 scrapy 中,可以定制化导出数据格式吗?scrapy 导出器学习
  6. PS图片处理:凌乱图片变炫彩背景(转)
  7. 使用python控制eTM-3020C程控电源
  8. java毕业设计延安市图书馆管理Mybatis+系统+数据库+调试部署
  9. 【Vivado那些事儿】Vivado Schematic中的实线和虚线有什么区别?
  10. 信息管理毕业设计题目大全