[我的第一个线段树]忠诚2
【题目描述】
老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。
在询问过程中账本的内容可能会被修改
【输入格式】
输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。
接下来每行为3个数字,第一个p为数字1或数字2,第二个数为x,第三个数为y
当p=1 则查询x,y区间
当p=2 则改变第x个数为y
【输出格式】
输出文件中为每个问题的答案。具体查看样例。
【样例输入】
10 3
1 2 3 4 5 6 7 8 9 10
1 2 7
2 2 0
1 1 10
【样例输入】
2 0
【分析】
这是一道用来练习线段树的例题。
如果你是刚开始看线段树,请先找其他的资料了解它。
我认为RMQ的线段树需要注意的地方:
- pass过程对mark和key的传递。
- add过程中第一个条件的判断,首先PASS,然后MID,然后KEY。
- findmin过程,第一个条件判断,首先PASS,然后MID。
以下为通过了此题的代码。
/* 1.建树 2.传递更改 3.修改区间值 4.查找最值 */ #include <stdio.h> #include <iostream> #define MAXN 900010 using namespace std; struct ss { int ls,rs,l,r,mark,key; } t[MAXN]; int a[MAXN]; int tot,root,x,y,z,n,m; void build(int *x,int l,int r) { *x = ++tot; t[*x].l = l; t[*x].r = r; if (l == r) t[*x].key = a[l]; else { int mid = (l + r) >> 1; build(&t[*x].ls,l,mid); build(&t[*x].rs,mid + 1,r); t[*x].key = min(t[t[*x].ls].key,t[t[*x].rs].key); } } void pass(int x) { if (t[x].l != t[x].r) { t[t[x].ls].key += t[x].mark; t[t[x].ls].mark += t[x].mark; t[t[x].rs].key += t[x].mark; t[t[x].rs].mark += t[x].mark; } t[x].mark = 0; } void add(int x,int st,int en,int va) { if ((st <= t[x].l) && (en >= t[x].r)) { t[x].key += va; t[x].mark += va; } else { pass(x); int mid = (t[x].l + t[x].r) >> 1; if (mid >= en) add(t[x].ls,st,en,va); else if (mid + 1 <= st) add(t[x].rs,st,en,va); else { add(t[x].ls,st,en,va); add(t[x].rs,st,en,va); } t[x].key = min(t[t[x].ls].key,t[t[x].rs].key); } } int findmin(int x,int st,int en) { pass(x); if ((st <= t[x].l) && (en >= t[x].r)) return t[x].key; int mid = (t[x].l + t[x].r) >> 1,temin = 10000010; if (mid >= st) temin = min(temin,findmin(t[x].ls,st,en)); if (mid + 1 <= en) temin = min(temin,findmin(t[x].rs,st,en)); return temin; } int main() { freopen("sample.in","r",stdin); freopen("sample.out","w",stdout); scanf("%d%d",&n,&m); for (int i = 1;i <= n;++i) scanf("%d",&a[i]); build(&root,1,n); for (int i = 1;i <= m;++i) { scanf("%d%d%d",&x,&y,&z); if (x == 1) printf("%d ",findmin(root,y,z)); else { x = a[y]; a[y] = z; add(root,y,y,z - x); } } return 0; }