题目链接:http://oj.ismdeep.com/contest/Problem?id=1284&pid=0

A: Ocean的礼物

Time Limit: 5 s      Memory Limit: 128 MB     

Submit My Status

Problem Description

皇家理工存在一段很神奇的路段,这段路由nn 个格子组成,每个格子都有一个数字,你可以走这段路的任意一段。这段路的神奇之处就在于,如果你所处的这个格子数字和你经过的前一个格子数字不相同的话,你就可以获得一个礼物(初始一定可以获得礼物)。现在Ocean想知道,给定任意路段的左边界和右边界,问若走这段路可以获得多少礼物。不过幸运的是,Ocean很快就解决了,并且获得了大量的礼物。玩的十分开心。但是有一天,这段路神奇的发生了改变。它不但会给你礼物。它还可能随时的改变其任意某处的格子上的数字。这下Ocean可就犯愁了,他想知道任意一段路可以获得的礼物是多少。聪明的你可以帮下他吗?

Input

第一行输入一个整数nn ,代表格子数。(1≤n≤106)(1≤n≤106)

第二行输入nn 个整数xx 。(1≤x≤108)(1≤x≤108)

第三行输入一个整数mm ,代表mm 次操作。(1≤m≤2∗105)(1≤m≤2∗105)

接下来第四行到3+m3+m 行每行33 个数op,x,yop,x,y 。

若op=1op=1 则把xx 处的数修改为yy 。(1≤x≤n,1≤y≤108)(1≤x≤n,1≤y≤108)

若op=2op=2 ,询问区间[x,y][x,y] 内可以获得的礼物数。(1≤x≤y≤n)(1≤x≤y≤n)

Output

对于每个询问输出一个整数,代表可以获得的礼物数

Sample Input

6
1 2 3 4 5 6
4
2 1 6
1 2 3
2 2 3
2 3 4

Sample Output

6
1
2

Hint

解题思路:做这题之前表示还没看过线段树,后来比赛完了,随便看了一篇关于线段树区间修改的文章,感觉可以运用到这题,然后我就硬生生把这题单点修改的问题当做区间修改来写了,就是每次修改点的时候判断与前面那个数是否一致,后面那个数是否一致,原来那个数,与前面那个数是否一致,与后面那个数是否一致,一共是16种情况,贼复杂,没办法还不太会用,还好时间限制比较松,运行了2000ms,AC了,先看下我的垃圾代码吧。。。下面再上正确代码。

具体看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt*2+1
#define pushup(rt) t[rt]=t[rt*2]+t[rt*2+1]
typedef long long ll;
const ll mod=1000000007;
const ll maxn=1000007;
int k=1;
ll t[maxn*4],lazy[maxn*4],a[maxn*4],num[maxn];void build(int l,int r,int rt)
{lazy[rt] = 0;if(l==r){t[rt]=a[k++];//scanf("%lld",&t[rt]);return ;}int m = (l+r)/2;build(lson);build(rson);pushup(rt);
}
void pushdown(int l,int r,int rt)
{if(lazy[rt]){lazy[rt*2] += lazy[rt];lazy[rt*2+1] += lazy[rt];t[rt*2] += l*lazy[rt];t[rt*2+1] += r*lazy[rt];lazy[rt] = 0;}
}
void update(int L,int R,int C,int l,int r,int rt)
{if(L<=l&&r<=R){t[rt] += (r-l+1)*C;lazy[rt] += C;return ;}int m = (l+r)/2;pushdown(m-l+1,r-m,rt);if(L<=m)update(L,R,C,lson);if(R>m)update(L,R,C,rson);pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{if(L<=l&&r<=R)return t[rt];int m = (l+r)/2;pushdown(m-l+1,r-m,rt);ll ans = 0;if(L<=m)ans += query(L,R,lson);if(R>m)ans += query(L,R,rson);return ans;
}int n,q,op,x;
ll y;int main()
{while(scanf("%d",&n)!=EOF){a[1]=1;for(int i=1;i<=n;i++){scanf("%lld",&num[i]);if(i>1&&num[i]!=num[i-1])a[i]=1;if(i>1&&num[i]==num[i-1])a[i]=0;}num[0]=num[n+1]=0;build(1,n,1);scanf("%d",&q);while(q--){scanf("%d",&op);scanf("%d%lld",&x,&y);if(op==1){if(num[x]!=num[x-1]&&num[x]!=num[x+1]){if(y!=num[x-1]&&y!=num[x+1])continue;else if(y==num[x-1]&&y!=num[x+1])update(x,x,-1,1,n,1);else if(y!=num[x-1]&&y==num[x+1])update(x+1,x+1,-1,1,n,1);elseupdate(x,x+1,-1,1,n,1);}else if(num[x]==num[x-1]&&num[x]!=num[x+1]){if(y!=num[x-1]&&y!=num[x+1])update(x,x,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1])continue;else if(y!=num[x-1]&&y==num[x+1]){update(x,x,1,1,n,1);update(x+1,x+1,-1,1,n,1);}elseupdate(x+1,x+1,-1,1,n,1);}else if(num[x]!=num[x-1]&&num[x]==num[x+1]){if(y!=num[x-1]&&y!=num[x+1])update(x+1,x+1,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1]){update(x,x,-1,1,n,1);update(x+1,x+1,1,1,n,1);}else if(y!=num[x-1]&&y==num[x+1])continue;elseupdate(x,x,-1,1,n,1);}else{if(y!=num[x-1]&&y!=num[x+1])update(x,x+1,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1])update(x+1,x+1,1,1,n,1);else if(y!=num[x-1]&&y==num[x+1])update(x,x,1,1,n,1);elsecontinue;}num[x]=y;}else{if(num[x]==num[x-1])printf("%lld\n",query(x,y,1,n,1)+1);elseprintf("%lld\n",query(x,y,1,n,1));}}}return 0;
}

正确思路:构建线段树时,一个节点保存三个信息,所在区间的不同的线段个数,区间的左边界和右 边界,合并区间时,比较左子区间的右边界和右子区间的左边界,若相等,就是两个区间 的不相同的线段树个数相加减一。

正确代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cstdlib>
#include <iomanip>
#include <cmath>
#include <cassert>
#include <ctime>
#include <map>
#include <set>
using namespace std;
#pragma comment(linker, "/stck:1024000000,1024000000")
#pragma GCC diagnostic error "-std=c++11"
#define lowbit(x) (x&(-x))
#define max(x,y) (x>=y?x:y)
#define min(x,y) (x<=y?x:y)
#define MAX 100000000000000000
#define MOD 1000000007
#define esp 1e-9
#define pi acos(-1.0)
#define ei exp(1)
#define PI 3.1415926535897932384626433832
#define ios() ios::sync_with_stdio(true)
#define INF 0x3f3f3f3f
#define mem(a) (memset(a,0,sizeof(a)))
typedef long long ll;
const int maxn=1000006;
int tree[maxn<<2][3];
int n,m,x,y,op;
void pushup(int root)
{tree[root][2]=tree[root<<1][2]+tree[root<<1|1][2];tree[root][0]=tree[root<<1][0];tree[root][1]=tree[root<<1|1][1];if(tree[root<<1][1]==tree[root<<1|1][0]) tree[root][2]--;//合并区间时,比较左子区间的右边界和右子区间的左边界,若相//等,就是两个区间 的不相同的线段树个数相加减一
}
void build(int l,int r,int root)
{if(l==r){scanf("%d",&tree[root][0]);   //tree[root][0]区间的左边界tree[root][1]=tree[root][0];  //tree[root][1]区间的右边界tree[root][2]=1;    //tree[root][2]所在区间不同的线段个数return ;}int mid=l+r>>1;build(l,mid,root<<1);build(mid+1,r,root<<1|1);pushup(root);
}
void update(int pos,int val,int l,int r,int root)
{if(l==r){tree[root][0]=tree[root][1]=val;return ;}int mid=l+r>>1;if(pos<=mid) update(pos,val,l,mid,root<<1);else update(pos,val,mid+1,r,root<<1|1);pushup(root);
}
int query(int L,int R,int l,int r,int root)
{if(L<=l && R>=r) return tree[root][2];int ans=0,mid=l+r>>1;if(L<=mid) ans+=query(L,R,l,mid,root<<1);if(R>mid) ans+=query(L,R,mid+1,r,root<<1|1);if(L<=mid && R>mid && tree[root<<1][1]==tree[root<<1|1][0]) ans--;return ans;
}
int main()
{scanf("%d",&n);build(1,n,1);scanf("%d",&m);while(m--){scanf("%d%d%d",&op,&x,&y);if(op==1) update(x,y,1,n,1);else printf("%d\n",query(x,y,1,n,1));}return 0;
}

转载于:https://www.cnblogs.com/zjl192628928/p/9473191.html

Ocean的礼物(线段树单点修改)相关推荐

  1. codeforces round #576 div2 D Welfare State(线段树)[单点修改+区间修改]

    题意:有一些数字,以及一些操作.操作一是单点修改,输入1 b c,将位置b改成c,操作二是输入2 a,将不大于a的数全部改成a.求更改完毕后的数. tag的运用:tag是对被覆盖区间上加一个标记,那么 ...

  2. HDU1754 I Hate It (线段树单点修改+区间查询)

    题目链接:传送门 解题思路:从题目中我们很明显知道只有两种操作,第一种是查询\([A,B]\)范围内学生成绩的最大值,典型的RMQ,第二种操作是将A的成绩改为B,而不是改为B的成绩,请仔细体会.(当然 ...

  3. 树链剖分+线段树 单点修改 区间求和 模板

    马上要去西安打邀请赛了,存下板子 首先是vector存图的: #include<bits/stdc++.h> using namespace std; #define ll long lo ...

  4. HDU1754 —— I Hate It 线段树 单点修改及区间最大值

    题目链接:https://vjudge.net/problem/HDU-1754 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.  这让很多学生很反感. 不管你喜不 ...

  5. python:线段树区间修改 + 区间查询 模板 + 坑点总结

    from functools import reduceclass SegTree:'''支持增量更新,覆盖更新,序列更新,任意RMQ操作基于二叉树实现初始化:O(1)增量更新或覆盖更新的单次操作复杂 ...

  6. HDU - 1166敌兵布阵+HDU-1754 I Hate It (线段树单点更新——累加/最大值)

    线段树单点更新,模板题 HDU1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和T ...

  7. HDUOJ----1166敌兵布阵(线段树单点更新)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  8. poj 2892---Tunnel Warfare(线段树单点更新、区间合并)

    题目链接 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensiv ...

  9. 【模板】线段树区间修改

    区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v ...

最新文章

  1. JSP、JAVA获取各种路径总结
  2. debain apt oracle jdk,debian安装oracle jdk
  3. html 入门例子(二) 折行
  4. 向linux内核加入系统调用新老内核比較
  5. blp模型 上读下写_Golang 并发模型系列:1. 轻松入门流水线模型
  6. 过程(栈帧结构是干货)
  7. 第11章 进入保护模式
  8. 大数学家陶哲轩谈时间管理与高效工作的方法
  9. finalshell远程安装oracle,安装oracle的问题
  10. NLP --- 条件随机场CRF详解
  11. centos7.2 开发 部署 .net core
  12. Atitit js nodejs 图像处理压缩缩放算法 attilax总结
  13. 网络管理助力节约IT运维成本
  14. 网络新手ip隐藏器_什么是高防IP,高防IP原理是什么
  15. CronTrigger(重要,非常强大)
  16. 嵌入式软件工程师面试遇到的经典题目
  17. php js轮播图片代码,js图片轮播手动切换效果实例代码
  18. 路由器温度测试软件,教你增强小米路由WEB管理(一)——添加CPU温度显示
  19. 遥远的路:【码农】的成长困惑
  20. echarts饼状图

热门文章

  1. MongoDB 命令速查表
  2. Flask对请求的处理
  3. 管理表空间和数据文件——维护表空间——设置默认表空间和删除表空间和删除数据文件盒临时文件...
  4. oracle提供的有用函数(待续)
  5. C#写的一个代码生成器
  6. 为什么民航单位免费给查胸部CT+为什么天气预报中有风向
  7. no instance(s) of type variable(s) X exist so that DataSource<X> conforms to DataStream<Order>
  8. linux下面的安卓模拟器genymotion运行taptap游戏-还没弄完
  9. 知乎上砍手豪关于kaggle的观点(转载)
  10. sublime无法输入中文(转)