标签:线段树
线段树:
图中的元素【a,b】表示该节点存储的值是在a到b内的结果(最大值或者和)。其根节点为c的话,其下面两个子树节点的序号为 c*2 和 c*2+1
区间最大值
题目:
5 6 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 2 9 Q 1 5
5 6 5 9
---改自 飘过的小牛
#include<cstdio> #include<algorithm> #include<cmath> #include <iostream> using namespace std; #define lson l, m, root << 1 #define rson m + 1, r, root << 1 | 1 const int N = 200010; int segtree[N << 1 + 10]; //开2倍 void PushUp(int root) //节点保存区间最大值 { segtree[root] = max(segtree[root << 1], segtree[root << 1 | 1]); } void Build_Tree(int l, int r, int root) { if(l == r) { scanf("%d", &segtree[root]); //cout<<root<<"<-"<<endl; return ; } int m = (l + r) >> 1; Build_Tree(lson); Build_Tree(rson); PushUp(root); } void Update(int pos, int data, int l, int r, int root) { if(l == r) { segtree[root] = data; return ; } int m = (l + r) >> 1; if(pos <= m) Update(pos, data, lson); else Update(pos, data, rson); PushUp(root); } int Query(int L, int R, int l, int r, int root) { int sum = -9999999; if(L <= l && r <= R) return segtree[root]; int m = (l + r) >> 1; if(L <= m) sum = max(sum, Query(L, R, lson)); if(R > m) sum = max(sum, Query(L, R, rson)); return sum; } int main() { int num, que; char ope; int a, b; while(scanf("%d%d", &num, &que) != EOF) { Build_Tree(1, num, 1); //for(int i=0;i<num*2;i++) // cout<<segtree[i]<<" "; //cout<<endl; for(int i = 0; i < que; ++i) { scanf("%*c%c %d %d", &ope, &a, &b); if(ope == ‘U‘) Update(a, b, 1, num, 1); else printf("%d\n", Query(a, b, 1, num, 1)); } } return 0; }
题目:区间求和
南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。
小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。
南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。
5 6 1 2 3 4 5 QUERY 1 3 ADD 1 2 QUERY 1 3 ADD 2 3 QUERY 1 2 QUERY 1 5
6 8 8 20
--
#include<stdio.h> int sum[3000000]; void build(int b, int e, int index) { if(b==e) { scanf("%d", &sum[index]); return; } int mid = (b+e)/2, lchild=index<<1 ,rchild=lchild|1; build(b, mid, lchild); build(mid+1, e, rchild); sum[index] = sum[lchild] + sum[rchild]; } int query(int qb, int qe, int b, int e, int index) { if(qb<=b && e<=qe) return sum[index]; int mid = (b+e)/2, lchild=index<<1 ,rchild=lchild|1, lr=0, rr=0; if(qb<=mid)lr = query(qb, qe, b, mid, lchild); if(qe>mid) rr = query(qb, qe, mid+1, e,rchild); return lr+rr; } void update(int b, int e, int node, int num, int index) { if(b==e && e==node) { sum[index]+=num; return; } int mid = (b+e)/2, lchild=index<<1 ,rchild=lchild|1; if(node<=mid)update(b, mid, node, num, lchild); else update(mid+1, e, node, num, rchild); sum[index] += num; } int main() { int n, k, b, e; char str[10]; scanf("%d %d", &n, &k); build(1, n, 1); for(int i=0; i<k; i++) { scanf("%s %d %d", str, &b, &e); if(str[0]==‘Q‘) printf("%d\n", query(b, e, 1, n, 1)); else update(1, n, b, e, 1); } return 0; }
题目:蓝桥杯练习题目-综合了区间最大和区间和
有n个格子,从左到右放成一排,编号为1-n。
共有m次操作,有3种操作类型:
1.修改一个格子的权值,
2.求连续一段格子权值和,
3.求连续一段格子的最大值。
对于每个2、3操作输出你所求出的结果。
第一行2个整数n,m。
接下来一行n个整数表示n个格子的初始权值。
接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。
有若干行,行数等于p=2或3的操作总数。
每行1个整数,对应了每个p=2或3操作的结果。
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
#include <cstdio> #include <iostream> using namespace std; const int MAX = 100110; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 int sum[MAX << 2], segs[MAX << 2], maxv[MAX << 2];//区间和-区间值-区间最大 inline void push_up(int rt){ sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; maxv[rt] = max(maxv[rt << 1], maxv[rt << 1 | 1]); } void build_up(int l, int r, int rt){ if(l == r){ scanf("%d", &segs[rt]); sum[rt] = segs[rt]; maxv[rt] = segs[rt]; return; } int m = (l + r) >> 1; build_up(lson); build_up(rson); push_up(rt); } void update(int l, int r, int rt, int p, int v){ if(l == r){ segs[rt] = v; maxv[rt] = v; sum[rt] = v; return; } int m = (l + r) >> 1; if(p <= m)update(lson, p, v); else update(rson, p, v); push_up(rt); } int query_sum(int L, int R, int l, int r, int rt){ if(L <= l && r <= R){ return sum[rt]; } int ret = 0; int m = (l + r) >> 1; if(L <= m)ret += query_sum(L, R, lson); if(R > m)ret += query_sum(L, R, rson); return ret; } int query_max(int L, int R, int l, int r, int rt){ if(L <= l && r <= R){ return maxv[rt]; } int ret = -1; int m = (l + r) >> 1; if(L <= m)ret = max(ret, query_max(L, R, lson)); if(R > m)ret = max(ret, query_max(L, R, rson)); return ret; } int main(){ int n, m; cin >> n >> m; build_up(1, n, 1); while(m--){ int p, x, y; scanf("%d%d%d", &p, &x, &y); if(p == 1){ update(1, n, 1, x, y); }else if(p == 2){ printf("%d\n", query_sum(x, y, 1, n, 1)); }else{ printf("%d\n", query_max(x, y, 1, n, 1)); } } return 0; }
题目:
掺杂几何知识
Time Limit: 2000MS | Memory Limit: 65536K | |||
Total Submissions: 3012 | Accepted: 806 | Special Judge |
Description
Input
Output
Sample Input
2 1 10 5 1 90 3 2 5 5 5 1 270 2 90
Sample Output
5.00 10.00 -10.00 5.00 -5.00 10.00
#include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> using namespace std; #define lson i<<1 #define rson i<<1|1 #define lc l,mid,i<<1 #define rc mid+1,r,i<<1|1 const int L = 100000+10; const double pi = acos(-1.0); struct node { double x,y; int deg; int flag; } a[L<<2]; double set(int x) { return x*pi/180; } void work(int i,int deg)//求新坐标公式 { double r = set(deg); double x = a[i].x; double y = a[i].y; a[i].x = x*cos(r)-y*sin(r); a[i].y = x*sin(r)+y*cos(r); a[i].deg = (a[i].deg+deg)%360; } void pushup(int i) { a[i].x = a[lson].x+a[rson].x; a[i].y = a[lson].y+a[rson].y; } void pushdown(int i) { if(a[i].flag) { work(lson,a[i].flag); work(rson,a[i].flag); a[lson].flag+=a[i].flag; a[rson].flag+=a[i].flag; a[i].flag = 0; } } void init(int l,int r,int i) { a[i].x = a[i].y = 0; a[i].flag = a[i].deg = 0; if(l == r) { scanf("%lf",&a[i].y); return; } int mid = (l+r)>>1; init(lc); init(rc); pushup(i); } void insert(int l,int r,int i,int L,int R,int z) { if(L<=l && r<=R) { work(i,z); a[i].flag+=z; return ; } pushdown(i); int mid = (l+r)>>1; if(L<=mid) insert(lc,L,R,z); if(R>mid) insert(rc,L,R,z); pushup(i); } int query(int l,int r,int i,int x) { if(l == r) return a[i].deg; pushdown(i); int mid = (l+r)>>1; if(x<=mid) return query(lc,x); else return query(rc,x); } int main() { int n,m,x,y,flag = 1,i,j; while(~scanf("%d%d",&n,&m)) { init(0,n-1,1); if(!flag) printf("\n"); flag = 0; while(m--) { scanf("%d%d",&x,&y); int deg; deg = query(0,n-1,1,x-1)+180+y-query(0,n-1,1,x); //由于题目是逆时针转的,该计算是顺时针,要加上180度,将后面的棒看成依然在Y轴,所以要减去后一个的角度 insert(0,n-1,1,x,n-1,deg); printf("%.2f %.2f\n",a[1].x,a[1].y); } } return 0; }
线段树-区间单个点更新-区间和-区间最大,布布扣,bubuko.com
标签:线段树
原文地址:http://blog.csdn.net/wximo/article/details/25504775