【例题】【线段树】
来源:互联网 发布:java instanceof 编辑:程序博客网 时间:2024/05/29 19:13
1、
!!!!!注意讨论不能建树的情况
NKOJ 1321 数列操作问题
时间限制 : 10000 MS 空间限制 : 165536 KB
问题描述
假设有一列数{Ai}(1≤i≤n),支持如下两种操作:
将Ak的值加D。(k, D是输入的数)
输出As+As+1+…+At。(s, t都是输入的数,S≤T)
输入格式
第一行一个整数n,
第二行为n个整数,表示{Ai}的初始值≤10000。
第三行为一个整数m,表示操作数
下接m行,每行描述一个操作,有如下两种情况:
ADD k d (表示将Ak加d,1<=k<=n,d为数,d的绝对值不超过10000)
SUM s t (表示输出As+…+At)
输出格式
对于每一个SUM提问,输出结果
样例输入
5
1 2 3 2 4
5
SUM 1 2
SUM 1 5
ADD 1 2
SUM 1 2
SUM 1 5
样例输出
3
12
5
14
提示
M,N<=100000
/*
1、线段树是通过二分思想建立的一颗表示区间关系的树形结构.
2、节点数最多2n-1个
*/
#include<cstdio>#include<iostream>using namespace std;const int need=100003;struct fy{int a,b,le,ri,val;}tree[need*2];//记录左右儿子就开2×n//也可以{int a,b,val;}tree[need*4]i*2表示左儿子,i*2+1表示右儿子;不记左右儿子就开4×nint a[need];int tot=0,k,d;void build(int x,int y){ int s=++tot; tree[s].a=x,tree[s].b=y; //tree[s].val=suma[y]-suma[x-1]; if(x<y) { tree[s].le=tot+1; build(x,(x+y)/2); tree[s].ri=tot+1; build((x+y)/2+1,y); tree[s].val=tree[tree[s].le].val+tree[tree[s].ri].val; } else if(x==y) tree[s].val=a[x];}void add_(int s){ tree[s].val+=d; if(tree[s].le!=0&&tree[tree[s].le].a<=k&&tree[tree[s].le].b>=k) add_(tree[s].le); else if(tree[s].ri!=0&&tree[tree[s].ri].a<=k&&tree[tree[s].ri].b>=k) add_(tree[s].ri);}int sum_(int s){ if(k<=tree[s].a&&tree[s].b<=d) return tree[s].val; int ans=0; if(!(tree[tree[s].le].a>d||tree[tree[s].le].b<k)) ans+=sum_(tree[s].le); if(!(tree[tree[s].ri].a>d||tree[tree[s].ri].b<k)) ans+=sum_(tree[s].ri); /*或: if(k<=tree[tree[s].le].b&&tree[tree[s].le].a<=d) ans+=sum_(tree[s].le); if(k<=tree[tree[s].ri].b&&tree[tree[s].ri].a<=d) ans+=sum_(tree[s].ri); 也可以判断是否在区间内 */ return ans;}/*再或int sum_(int s){ if(d<tree[s].a||k>tree[s].b) return 0; if(k<=tree[s].a&&tree[s].b<=d) return tree[s].val; return sum_(s<<1)+sum_((s<<1)|1);}*/int main(){ int n;scanf("%d",&n); //int a; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); //suma[i]=suma[i-1]+a; } build(1,n); int m;scanf("%d",&m); string b; for(int i=1;i<=m;i++) { cin>>b;scanf("%d%d",&k,&d); if(b=="SUM") printf("%d\n",sum_(1)); else if(b=="ADD") add_(1); }}
2、
NKOJ 1344 人力资源管理
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
某公司有n个员工,每个员工有一个工作能力值(该值为60000以内的自然数)。
Tom是公司人力资源部门的主管,他可以进行如下3种操作:
1.Tom为公司招聘了一个能力值为x的新员工
2.Tom为公司辞退了一个能力值为y的员工
3.Tom要查出在所有员工能力值由高到低的排名中,能力值大于W的员工的人数
输入格式
第一行两个整数n,m 表示有n个员工,和tom的m项工作
接下来一行,n个整数,表示n个员工的能力值
接下来m行,每行有两个整数a,b(1<=b<=60000)。
a==1 表示招聘了一个能力值为b的新员工
a==2 表示辞退了一个能力值为b的员工(若没有能力值为b的员工,则该操作无效)
a==3 表示查出能力值>b的员工的个数,并输出结果
输出格式
若干行,每行一个整数,表示输入中所有a==3的操作的结果。
样例输入
样例输入1:
6 5
9 4 6 2 3 5
1 7
1 10
3 6
2 9
3 6
样例输入2:
4 4
4 1 2 5
1 3
3 3
2 4
3 1
样例输出
样例输出1:
3
2
样例输出2:
2
3
提示
n,m<=100000
思路:
1、每个员工的能力值在60000以内,所以建立一个表示区间[1,60001]的线段树
2、对于第三类查询,即为求b+1到max区间中的人数,注意当b+1大于max时直接输出0;
#include<iostream>#include<cstdio>using namespace std;const int need1=60003;const int need2=100003;struct fy{int a,b,le,ri,val;}t[need2*2];struct yf{int mold,num;}c[need2];int a[need2];int tot=0,k,ne=-need1;void build(int x,int y){ int s=++tot; t[s].a=x,t[s].b=y; if(x==y) { t[s].val=a[x]; return ; } t[s].le=tot+1;build(x,(x+y)/2); t[s].ri=tot+1;build((x+y)/2+1,y); t[s].val=t[t[s].le].val+t[t[s].ri].val;}void add_(int s){ if(t[s].a<=k&&k<=t[s].b) t[s].val++; if(t[s].le!=0&&t[t[s].le].a<=k&&k<=t[t[s].le].b) add_(t[s].le); else if(t[s].ri!=0&&t[t[s].ri].a<=k&&k<=t[t[s].ri].b) add_(t[s].ri);} void fire_(int s){ if(t[s].a<=k&&k<=t[s].b) t[s].val--; if(t[s].le!=0&&t[t[s].le].a<=k&&k<=t[t[s].le].b) fire_(t[s].le); else if(t[s].ri!=0&&t[t[s].ri].a<=k&&k<=t[t[s].ri].b) fire_(t[s].ri);}int cnt(int s){ if(k+1<=t[s].a&&t[s].b<=ne) return t[s].val; int ans=0,mid=(t[s].a+t[s].b)/2; if(k<mid) ans+=cnt(t[s].le); ans+=cnt(t[s].ri); return ans; }int main(){ int n,m;scanf("%d%d",&n,&m); for(int b,i=1;i<=n;i++) { scanf("%d",&b); if(ne<b) ne=b; a[b]++; } for(int i=1;i<=m;i++) { scanf("%d%d",&c[i].mold,&c[i].num); if(c[i].num>ne&&c[i].mold==1) ne=c[i].num; } build(1,ne); for(int i=1;i<=m;i++) { k=c[i].num; if(c[i].mold==2&&a[k]) { a[k]--; fire_(1); } else if(c[i].mold==1) { a[k]++; add_(1); } else if(c[i].mold==3) printf("%d\n",k>=ne?0:cnt(1)); }}
- 【例题】【线段树】
- 【例题】【线段树】lazy
- 线段树例题5
- 线段树例题集合
- 线段树典型例题--poj2482
- 线段树典型例题--poj2528
- 线段树典型例题--poj2828
- 线段树典型例题--poj3277
- 线段树典型例题--poj2777
- 【例题】【线段树】连续区间
- 线段树讲解及例题
- 线段树典型例题--poj3667 hotel
- 蓝桥杯 操作格子(线段树例题)
- 【例题】【线段数】lazy_
- 线段树-基础,典型例题的完整代码
- 线段树与动态规划(例题:poj2374,HDU3016)
- 可持久化线段树/主席树 基础原理和例题
- 数据结构_线段树_例题_ I Hate It(HDU 1754)
- MVC
- Android 回调函数callBack
- ERROR 1366 (HY000): Incorrect string value: '\xC6\xF4\xD3\xC3' for column 'name' at row 1
- Java开发中的23种设计模式详解(转)
- luogu1151 亲戚
- 【例题】【线段树】
- 特别注意用UpdateData(FALSE)还是SetDlgItemText(IDC_EDIT_Coordinate, m_strCoor);
- POJ2352 Stars[树状数组]
- c语言,字符串转换成整数
- LeakCanary源码分析
- ReentrantLock介绍和实现
- UOJ #82. 【UR #7】水题生成器
- Servlet的监听器Listener
- (巩固基础篇)排序算法:①插入排序②希尔排序③冒泡排序④选择排序⑤快速排序