Ocean的礼物(线段树单点修改)
题目链接:http://oj.ismdeep.com/contest/Problem?id=1284&pid=0
A: Ocean的礼物
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=;
const ll maxn=;
int k=;
ll t[maxn*],lazy[maxn*],a[maxn*],num[maxn]; void build(int l,int r,int rt)
{
lazy[rt] = ;
if(l==r)
{
t[rt]=a[k++];
//scanf("%lld",&t[rt]);
return ;
}
int m = (l+r)/;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int l,int r,int rt)
{
if(lazy[rt])
{
lazy[rt*] += lazy[rt];
lazy[rt*+] += lazy[rt];
t[rt*] += l*lazy[rt];
t[rt*+] += r*lazy[rt];
lazy[rt] = ;
}
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
t[rt] += (r-l+)*C;
lazy[rt] += C;
return ;
}
int m = (l+r)/;
pushdown(m-l+,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)/;
pushdown(m-l+,r-m,rt);
ll ans = ;
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[]=;
for(int i=;i<=n;i++)
{
scanf("%lld",&num[i]);
if(i>&&num[i]!=num[i-])
a[i]=;
if(i>&&num[i]==num[i-])
a[i]=;
}
num[]=num[n+]=;
build(,n,);
scanf("%d",&q);
while(q--)
{
scanf("%d",&op);
scanf("%d%lld",&x,&y);
if(op==)
{
if(num[x]!=num[x-]&&num[x]!=num[x+])
{
if(y!=num[x-]&&y!=num[x+])
continue;
else if(y==num[x-]&&y!=num[x+])
update(x,x,-,,n,);
else if(y!=num[x-]&&y==num[x+])
update(x+,x+,-,,n,);
else
update(x,x+,-,,n,);
}
else if(num[x]==num[x-]&&num[x]!=num[x+])
{
if(y!=num[x-]&&y!=num[x+])
update(x,x,,,n,);
else if(y==num[x-]&&y!=num[x+])
continue;
else if(y!=num[x-]&&y==num[x+])
{
update(x,x,,,n,);
update(x+,x+,-,,n,);
}
else
update(x+,x+,-,,n,);
}
else if(num[x]!=num[x-]&&num[x]==num[x+])
{
if(y!=num[x-]&&y!=num[x+])
update(x+,x+,,,n,);
else if(y==num[x-]&&y!=num[x+])
{
update(x,x,-,,n,);
update(x+,x+,,,n,);
}
else if(y!=num[x-]&&y==num[x+])
continue;
else
update(x,x,-,,n,);
}
else
{
if(y!=num[x-]&&y!=num[x+])
update(x,x+,,,n,);
else if(y==num[x-]&&y!=num[x+])
update(x+,x+,,,n,);
else if(y!=num[x-]&&y==num[x+])
update(x,x,,,n,);
else
continue;
}
num[x]=y;
}
else
{
if(num[x]==num[x-])
printf("%lld\n",query(x,y,,n,)+);
else
printf("%lld\n",query(x,y,,n,));
}
}
}
return ;
}
正确思路:构建线段树时,一个节点保存三个信息,所在区间的不同的线段个数,区间的左边界和右 边界,合并区间时,比较左子区间的右边界和右子区间的左边界,若相等,就是两个区间 的不相同的线段树个数相加减一。
正确代码:
#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=;
int tree[maxn<<][];
int n,m,x,y,op;
void pushup(int root)
{
tree[root][]=tree[root<<][]+tree[root<<|][];
tree[root][]=tree[root<<][];
tree[root][]=tree[root<<|][];
if(tree[root<<][]==tree[root<<|][]) tree[root][]--;
//合并区间时,比较左子区间的右边界和右子区间的左边界,若相
//等,就是两个区间 的不相同的线段树个数相加减一
}
void build(int l,int r,int root)
{
if(l==r)
{
scanf("%d",&tree[root][]); //tree[root][0]区间的左边界
tree[root][]=tree[root][]; //tree[root][1]区间的右边界
tree[root][]=; //tree[root][2]所在区间不同的线段个数
return ;
}
int mid=l+r>>;
build(l,mid,root<<);
build(mid+,r,root<<|);
pushup(root);
}
void update(int pos,int val,int l,int r,int root)
{
if(l==r)
{
tree[root][]=tree[root][]=val;
return ;
}
int mid=l+r>>;
if(pos<=mid) update(pos,val,l,mid,root<<);
else update(pos,val,mid+,r,root<<|);
pushup(root);
}
int query(int L,int R,int l,int r,int root)
{
if(L<=l && R>=r) return tree[root][];
int ans=,mid=l+r>>;
if(L<=mid) ans+=query(L,R,l,mid,root<<);
if(R>mid) ans+=query(L,R,mid+,r,root<<|);
if(L<=mid && R>mid && tree[root<<][]==tree[root<<|][]) ans--;
return ans;
}
int main()
{
scanf("%d",&n);
build(,n,);
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&op,&x,&y);
if(op==) update(x,y,,n,);
else printf("%d\n",query(x,y,,n,));
}
return ;
}
Ocean的礼物(线段树单点修改)的更多相关文章
- POJ 3321 Apple Tree(DFS序+线段树单点修改区间查询)
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 25904 Accepted: 7682 Descr ...
- HDU - 1754 线段树-单点修改+询问区间最大值
这个也是线段树的经验问题,待修改的,动态询问区间的最大值,只需要每次更新的时候,去把利用子节点的信息进行修改即可以. 注意更新的时候区间的选择,需要对区间进行二分. #include<iostr ...
- HDU 1166 敌兵布阵 <线段树 单点修改 区间查询>
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- 校内模拟赛T5:连续的“包含”子串长度( nekameleoni?) —— 线段树单点修改,区间查询 + 尺取法合并
nekameleoni 区间查询和修改 给定N,K,M(N个整数序列,范围1~K,M次查询或修改) 如果是修改,则输入三个数,第一个数为1代表修改,第二个数为将N个数中第i个数做修改,第三个数为修改成 ...
- A.Ocean的礼物线段树
A: Ocean的礼物 Time Limit: 2 s Memory Limit: 128 MB Submit My Status Problem Description 皇家理工存在一段很神 ...
- HDU - 1166 敌兵布阵 方法一:(线段树+单点修改,区间查询和) 方法二:利用树状数组
C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于 ...
- HDU1754 I hate it(线段树 单点修改)
好久没打线段树,来一道练练手,但说句实话,I really hate it!!!! 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管 ...
- HDU 1754 I Hate It 【线段树单点修改 维护区间最大值】
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others ...
- Coderforces 85 D. Sum of Medians(线段树单点修改)
D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standard i ...
随机推荐
- 【Python3练习题 014】 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。
a.b只要数字a能被数字b整除,不论b是不是质数,都算是a的因子.比如:8的质因子是 2, 2, 2,但8的因子就包括 1,2,4. import math for i in range(2, 1 ...
- js 通过url获取里面的参数值
场景描述:当我们从一个页面要带有一两个值跳转到另一个页面,另一个页面要使用这些参数的时候,我们就需要通过js获取这些参数啦. 先贴上代码: function getQueryString(name) ...
- [转帖]SAP一句话入门:Sales and Distribution
SAP一句话入门:Sales and Distribution http://blog.vsharing.com/MilesForce/A616565.html SD是Sales and Distri ...
- 游标cursor案例
- jenkins配置SSH远程服务器连接
之前用jenkins做了一个自动发布测试,配置任务的Post Steps时,选择的是执行shell命令.如下图: 这是在本192.168.26.233服务器上测试的,此服务器上运行jenkins,to ...
- flutter开发vscode用模拟器调试
android studio的太重,我装的是android sdk,使用avd的模拟器启动黑屏 启动夜神模拟器(已卸载) 建立连接: adb connect 127.0.0.1:62001 (夜 ...
- python爬虫之scrapy的pipeline的使用
scrapy的pipeline是一个非常重要的模块,主要作用是将return的items写入到数据库.文件等持久化模块,下面我们就简单的了解一下pipelines的用法. 案例一: items池 cl ...
- struts2 核心过滤器的配置
<!-- struts2 过滤器核心配置--> <filter> <filter-name>struts2</filter-name> <filt ...
- YUV格式与RGB格式
YUV420介绍: YUV420格式是指,每个像素都保留一个Y(亮度)分量,而在水平方向上,不是每行都取U和V分量,而是一行只取U分量,则其接着一行就只取V分量,以此重复(即4:2:0, 4:0:2, ...
- JQ用法
jQuery简称jq,是一款同prototype一样优秀js开发库类,特别是对css和XPath的支持,使我们写js变得更加方便!如果你不是个js高手又想写出优 秀的js效果,jq可以帮你达到目的!下 ...