HDU-5367 digger(线段树区间合并)
来源:互联网 发布:excel如何导入外部数据 编辑:程序博客网 时间:2024/04/30 13:03
digger
Accepts: 3
Submissions: 64
Time Limit: 8000/4000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
地主小花有n座山,这些山在地主家门前排成一条直线。这些山一开始均有相同的高度。 每一天,小花都会要求ZJiaQ开挖机把几座山挖掉一定高度,或者给一些山堆上一些高度。并且要求报告ZJiaQ报告现在有多少座山属于“高山脉”当一排山的高度相等,并且比这排山左边和右边的山要高时,这排山被称为高山脉。当然,最左边和最右边的山不可能是“高山脉”的一部分
输入描述
输入有多组数据每组数据第一行有3个整数n,q,r(1<=n<=10^9,1<=q<=50000,0<=r<=1000)接下来的q行,每行有3个整数l,r,val(1<=l<=r<=n,-1000<=val<=1000),表示从第l座山到第r座山的高度变更了val。每次输入的l,r,val需要与前一次的答案进行异或操作得到的值才是真正的l,r,val。第一次输入的l,r,val不需要。
输出描述
输出q行,每行一个数字表示答案
输入样例
5 5 04 5 872 5 -483 3 174 5 -1715 5 -494
输出样例
00011
写这道题真的是呕心沥血,pushup的时候rcnt写成lcnt,结果测评爆的是RE,害得我一直在找栈哪里有问题。。。最后参考了鸟神的代码,也通过这道题让我对线段树区间合并有了新的认识。
这道题有个毒瘤的地方是n<1e9,因此不能直接开n这么大的线段树,想到要用离散做的时候,发现查询的区间是动态的:每次输入l,r,val后要与前面的ans进行或运算,因此无法用离线的离散化来做。但我们可以模仿可持久化线段树的做法,动态插入节点(不过不用保留历史值,因此还是静态的线段树)
知道要用线段树做了,那么该怎么维护区间合并这一过程呢?
假设我们现在要合并ls和rs这2段区间,合并后的区间为rt,设ls最右边的山高度为rh,从右往左第一个高度不等于rh的山高度为rp;设rs最左边的山高度为lh,从左往右第一个高度不等于lh的山高度为lp。
分情况讨论:
①rh > lh且rh > rp时,那么左边区间最右边那一段高度等于rh的山在区间rt中是“高山脉”;
②rh < lh且lh > lp时,那么右边区间最左边那一段高度等于lh的山在区间rt中是“高山脉”
因此对于每个区间,我们要维护3种变量:
①lh和rh:区间最左边和区间最右边山的高度;
②lcnt和rcnt:从左边开始高度等于lh的山的数量,从右边开始高度等于rh的山的数量;
③lp和rp:从左边开始第一个高度不等于lh的山的高度,从右边开始第一个高度不等于rh的山的高度
#include<bits/stdc++.h>using namespace std;typedef long long LL;const int MX = 2e6 + 5;const int INF = 0x3f3f3f3f;struct Node { int sum; //答案数量 int add; int len; //区间长度 int l, r; //区间范围 int lh, rh; //左边起连续的高度,右边起连续的高度 int lcnt, rcnt; //左右连续高度的数量 int lp, rp; //左边起第一个不连续的高度,右边起第一个不连续的高度 int ls, rs; //左右子树编号 void init(int _l, int _r) { sum = add = lh = rh = lp = rp = ls = rs = 0; l = _l; r = _r; len = lcnt = rcnt = r - l + 1; }} node[MX];int tot, n;void check(int &rt, int l, int r) { if (rt == 0) { rt = ++tot; node[rt].init(l, r); if (l == 1) node[rt].lh = INF; if (r == n) node[rt].rh = INF; }}void update(int rt, int c) { node[rt].add += c; node[rt].lh += c; node[rt].rh += c; node[rt].lp += c; node[rt].rp += c;}void PushUP(int rt) { int l = node[rt].l, r = node[rt].r; int m = (l + r) >> 1; check(node[rt].ls, l, m); check(node[rt].rs, m + 1, r); int ls = node[rt].ls, rs = node[rt].rs; node[rt].sum = node[ls].sum + node[rs].sum; node[rt].lh=node[ls].lh; node[rt].rh=node[rs].rh; node[rt].lp=node[ls].lp; node[rt].rp=node[rs].rp; node[rt].lcnt=node[ls].lcnt; node[rt].rcnt=node[rs].rcnt; if (node[ls].rcnt == node[ls].len) { if (node[ls].rh == node[rs].lh) { node[rt].lp = node[rs].lp; node[rt].lcnt = node[ls].len + node[rs].lcnt; } else { node[rt].lp = node[rs].lh; } } if (node[rs].lcnt == node[rs].len) { if (node[rs].lh == node[ls].rh) { node[rt].rp = node[ls].rp; node[rt].rcnt = node[rs].len + node[ls].rcnt; } else { node[rt].rp = node[ls].rh; } } if (node[ls].rh > node[rs].lh) { if (node[ls].rh > node[ls].rp && node[ls].rcnt < node[ls].len) node[rt].sum += node[ls].rcnt; } else if (node[ls].rh < node[rs].lh) { if (node[rs].lh > node[rs].lp && node[rs].lcnt < node[rs].len) node[rt].sum += node[rs].lcnt; } else { if (node[ls].rh > node[ls].rp && node[rs].lh > node[rs].lp && node[ls].rcnt < node[ls].len && node[rs].lcnt < node[rs].len) node[rt].sum += node[ls].rcnt + node[rs].lcnt; }}void PushDown(int rt) { if (node[rt].add) { int l = node[rt].l, r = node[rt].r; int m = (l + r) >> 1; check(node[rt].ls, l, m); check(node[rt].rs, m + 1, r); update(node[rt].ls, node[rt].add); update(node[rt].rs, node[rt].add); node[rt].add = 0; }}void update(int L, int R, int c, int l, int r, int &rt) { check(rt, l, r); if (L <= l && R >= r) { update(rt, c); return; } PushDown(rt); int m = (l + r) >> 1; if (L <= m) update(L, R, c, l, m, node[rt].ls); if (R > m) update(L, R, c, m + 1, r, node[rt].rs); PushUP(rt);}int main() { int m, p; //freopen("in.txt","r",stdin); while (~scanf("%d%d%d", &n, &m, &p)) { int ans = 0, root; tot = 0; root = ++tot; node[root].init(1,n); for (int i = 1, l, r, val; i <= m; i++) { scanf("%d%d%d", &l, &r, &val); l ^= ans; r ^= ans; val ^= ans; if(r<l) swap(l,r); update(l, r, val, 1, n, root); ans=node[1].sum; printf("%d\n",ans); } } return 0;}
阅读全文
0 0
- HDU-5367 digger(线段树区间合并)
- hdu 5367 digger(线段树)
- 【HDU】5367 digger【动态线段树】
- hdu 5367(线段树+区间合并)
- 【线段树】 HDOJ 5367 digger
- hdu 3308(线段树的区间合并)
- hdu 3308 LCIS (线段树+单点更新+区间合并)
- HDU 3397 Sequence operation 线段树(区间合并)
- HDU 3911 Black And White(线段树区间合并)
- 【HDU】3308 LCIS (线段树-区间合并)
- 【Hdu】1540 Tunnel Warfare(线段树|区间合并)
- HDU 3308 LCIS(线段树区间合并)
- HDU - 3308 - LCIS (线段树 - 区间合并)
- HDU 5316 Magician(线段树区间合并入门)
- hdu 5316 Magician(线段树区间合并)
- HDU 3308 LCIS(线段树区间合并)
- HDU 5316 Magician(线段树 区间合并)
- HDU 3308 LCIS(线段树区间合并 单点更新)
- The first time
- acl权限验证
- Feel Good POJ
- Win+Debian下更改硬盘分区的影响及解决办法
- Python爬虫Xpath和lxml类库系列之九
- HDU-5367 digger(线段树区间合并)
- c++中new/delete与malloc/free的区别与联系
- 菱形继承
- git--多人合作
- 【BZOJ】3343 教主的魔法 分块
- UVA
- nfs的初探
- android_在线播放器
- Salty Fish