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;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 监控主机密码忘了怎么办 加购物车不下单怎么办 绑定qq账号消息不见了怎么办 现在的注册微信怎么办 爱奇艺手机号码被别人绑定了怎么办 手机号码换了支付宝账号怎么办 qq换手机号了怎么办呢 公司被注销了公众号怎么办 qq号被限制查找怎么办 qq号别人查找不到怎么办 qq邮箱已被注册怎么办 微信付款没网络怎么办 天猫买的假货店铺关门了怎么办 鞋小了半码怎么办 迅雷会员种子不能加速怎么办 迅雷会员为什么不能加速怎么办 持有st创智股票怎么办 租的房子床坏了怎么办 宜家定时器不响怎么办 新插座插不进去怎么办 本溪人社app打不开怎么办 南宁电车超过上牌时间怎么办 苹果6s降频怎么办 0首付手机还不起怎么办 乐才app登录不上怎么办 买了笔记本网要怎么办? 电脑连接不上网络怎么办 电脑上没网络了怎么办 手机返回键不好使怎么办 笔记本无线网连接受限怎么办 魅族打电话图标没有了怎么办 京东价格保护后发票怎么办 淘宝未满十八岁怎么办 SVN提交时代码冲突怎么办 京东自营没货了怎么办 京东下了单 没货怎么办 万达广场购物卡怎么办 京东白条没额度怎么办 京东退款还收到货怎么办 退货不想要货了怎么办 安装微擎创建数据库失败怎么办