2018 UESTC 线段树专题
A - 一棵简单的线段树
A[1...n]初始全为0.
1. 给两个数p 和 x(1≤p≤n),单点更新 A[p] <- x
2. 给两个数L和R (1≤L<R≤n), L到R区间里这几个数去掉一个最大值和一个最小值后剩下的数的和是多少。用到了max, min, sum
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 const int maxn = 1e6+6; 8 #define LL long long 9 #define INF 0x7fffffff 10 11 int n,a[maxn],q; 12 13 struct node 14 { 15 int l,r,mx,mn; 16 long long sum; 17 void update(long long x) {sum=x;mx=x;mn=x;} 18 }tree[maxn*4]; 19 20 void push_up(int x) 21 { 22 tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; 23 tree[x].mx=max(tree[x<<1].mx,tree[x<<1|1].mx); 24 tree[x].mn=min(tree[x<<1].mn,tree[x<<1|1].mn); 25 } 26 27 void build(int x,int l,int r) 28 { 29 tree[x].l=l,tree[x].r=r; 30 tree[x].sum=0,tree[x].mx=0,tree[x].mn=0; 31 if(l==r) 32 { 33 tree[x].sum=tree[x].mx=tree[x].mn=a[l]; 34 } 35 else 36 { 37 int mid = (l+r)/2; 38 build(x<<1,l,mid); 39 build(x<<1|1,mid+1,r); 40 push_up(x); 41 } 42 } 43 44 void update(int x,int pos,long long val) 45 { 46 int L =tree[x].l, R = tree[x].r; 47 if(L==pos&&R==pos) 48 { 49 tree[x].update(val); 50 } 51 else 52 { 53 int mid = (L+R)/2; 54 if(mid>=pos)update(x<<1,pos,val); 55 if(pos>mid)update(x<<1|1,pos,val); 56 push_up(x); 57 } 58 } 59 60 long long query(int x,int l,int r) 61 { 62 int L =tree[x].l, R = tree[x].r; 63 if(l<=L&&R<=r) 64 return tree[x].sum; 65 else 66 { 67 long long ans=0; 68 int mid = (L+R)/2; 69 if(mid>=l)ans+=query(x<<1,l,r); 70 if(r>mid)ans+=query(x<<1|1,l,r); 71 push_up(x); 72 return ans; 73 } 74 } 75 76 int query_max(int x,int l,int r) 77 { 78 int L =tree[x].l, R = tree[x].r; 79 if(l<=L&&R<=r) 80 return tree[x].mx; 81 else 82 { 83 int ans=-1e9-2; 84 int mid = (L+R)/2; 85 if(mid>=l)ans=max(ans,query_max(x<<1,l,r)); 86 if(r>mid)ans=max(ans,query_max(x<<1|1,l,r)); 87 push_up(x); 88 return ans; 89 } 90 } 91 92 93 int query_min(int x,int l,int r) 94 { 95 int L =tree[x].l, R = tree[x].r; 96 if(l<=L&&R<=r) 97 return tree[x].mn; 98 else 99 { 100 int ans=1e9+2; 101 int mid = (L+R)/2; 102 if(mid>=l)ans=min(ans,query_min(x<<1,l,r)); 103 if(r>mid)ans=min(ans,query_min(x<<1|1,l,r)); 104 push_up(x); 105 return ans; 106 } 107 } 108 109 int main() { 110 scanf("%d",&n); 111 for(int i=1;i<=n;i++)a[i]=0; 112 build(1,1,n); 113 scanf("%d",&q); 114 for(int i=1;i<=q;i++) 115 { 116 int x,y,o; 117 scanf("%d%d%d",&o,&x,&y); 118 if(o==0)update(1,x,y); 119 else 120 { 121 long long sum=query(1,x,y); 122 int mx=query_max(1,x,y); 123 int mn=query_min(1,x,y); 124 printf("%lld\n",sum-mx-mn); 125 } 126 } 127 return 0; 128 }
B - 一棵普通的线段树
A[1...n]初始全为0。
一棵裸的区间修改、区间查询的线段树
1. 区间加v
2. 区间求和
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 1e6+6; 7 #define LL long long 8 #define INF 0x7fffffff 9 10 int n,q,a[maxn]; 11 12 struct node{ 13 int l, r; 14 LL sum, lazy; 15 void update(int x) { 16 sum += 1LL*(r-l+1)*x; 17 lazy += x; 18 } 19 }tree[maxn*4]; 20 21 void push_up(int x) { 22 tree[x].sum = tree[x<<1].sum + tree[x<<1|1].sum; 23 } 24 25 void push_down(int x) { 26 int lazy = tree[x].lazy; 27 if(lazy) { 28 tree[x<<1].update(lazy); 29 tree[x<<1|1].update(lazy); 30 tree[x].lazy = 0; 31 } 32 } 33 34 void build(int x, int l, int r) { 35 tree[x].l = l, tree[x].r = r; 36 tree[x].sum = tree[x].lazy = 0; 37 if(l == r) { 38 tree[x].sum = a[l]; 39 } 40 else { 41 int mid = (l+r) / 2; 42 build(x<<1, l, mid); 43 build(x<<1|1, mid+1, r); 44 push_up(x); 45 } 46 } 47 48 void update(int x, int l, int r, int val) { 49 int L = tree[x].l, R = tree[x].r; 50 if(l <= L && R <= r) { 51 tree[x].update(val); 52 } 53 else { 54 push_down(x); 55 int mid = (L+R) / 2; 56 if(mid >= l) update(x<<1, l, r, val); 57 if(r > mid) update(x<<1|1, l, r, val); 58 push_up(x); 59 } 60 } 61 62 LL query(int x, int l, int r) { 63 int L = tree[x].l, R = tree[x].r; 64 if(l <= L && R <= r) return tree[x].sum; 65 else { 66 push_down(x); 67 int mid = (L+R) / 2; 68 LL ans = 0; 69 if(mid >= l) ans += query(x<<1, l, r); 70 if(r > mid) ans += query(x<<1|1, l, r); 71 push_up(x); 72 return ans; 73 } 74 } 75 76 77 int main() { 78 scanf("%d",&n); 79 for(int i=1;i<=n;i++)a[i]=0; 80 build(1,1,n); 81 scanf("%d",&q); 82 for(int i=1;i<=q;i++) 83 { 84 int o,l,r,val; 85 scanf("%d%d%d%d",&o,&l,&r,&val); 86 if(o==0)update(1,l,r,val); 87 else printf("%lld\n",query(1,l,r)); 88 } 89 return 0; 90 }
C - 一棵像样的线段树
假设每个Ci = i , bn最大为n+1。
对于每个Ci,相当于询问b[i-ci] 到 b[i-1] 区间内最小未出现的数。
可以设s[x] 为x最后出现的位置。对于每个Ci,我们可以得到左区间 i - Ci;
s[1]= 0 , 其他位置初始化-1(其他值都未出现过,所以都满足s[x] < i - ci )
凡是s[x] < i - Ci 的x均未在区间内出现过,那么我们只要找出最小的x,满足:s[x] < i - ci 即可。
可以用线段树维护s[x] ,1 <= x <= n+1 , 区间的最小值。
每次给出左区间 i - ci ,就从最大的区间查询,如果左子树的最小值>=i-ci,就递归访问右子树,否则访问左子树。
最终区间长度为1时,l(或r)即为答案。
总结:可以发现b数组最多就是1到n,那么对于1到n开一棵线段树,每个结点储存当前数出现的最后的位置。因为我们要求的是 i-ci到i-1的范围内没有出现过的第一个数,
那么我们现在储存了每个数出现的最后的位置,那么我们就找一个这个位置不在i-ci到i-1的范围内且最小的数即可。因为我们线段树是默认1到n即从小到大,所以即尽可能地往左子树找,
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e6+6; 5 const int maxn = N<<2; 6 7 int n,a[N]; 8 int tree[maxn]; 9 int ans[N]; 10 11 void update_tree(int a, int b, int pos, int node, int value) { 12 if(a>b || a>pos || b<pos) return; 13 if(a==b) { 14 tree[node]=value; 15 return; 16 } 17 update_tree(a,(a+b)>>1,pos,node<<1,value); 18 update_tree(((a+b)>>1)+1,b,pos,(node<<1)|1,value); 19 tree[node]=min(tree[node<<1],tree[(node<<1)|1]); 20 } 21 22 int query_tree(int a, int b, int node, int value) { 23 if(a==b) return a; 24 if(tree[node<<1]<value) return query_tree(a,(a+b)>>1,node<<1,value); 25 else return query_tree(((a+b)>>1)+1,b,(node<<1)|1,value); 26 } 27 28 int main() { 29 int i; 30 scanf("%d", &n); 31 for(i=1;i<=n;i++) 32 { 33 scanf("%d", &a[i]); 34 } 35 for(i=1;i<=n;i++) 36 { 37 if(i==1)update_tree(1,1000003,1,1,1); 38 else update_tree(1,1000003,ans[i],1,i); 39 int l=i-a[i]+1; 40 ans[i+1]=query_tree(1,1000003,1,l); 41 } 42 for(i=2;i<=n+1;i++) 43 if(i<n+1)printf("%d ", ans[i]); 44 else printf("%d\n", ans[i]); 45 46 return 0; 47 } 48 49 #include <bits/stdc++.h> 50 using namespace std; 51 52 const int N = 1e6+6; 53 const int maxn = N<<2; 54 55 int n, a[N], ans[N]; 56 57 struct node 58 { 59 int l,r; 60 int min_left; 61 void update(int value){min_left=value;} 62 }tree[maxn]; 63 64 void push_up(int x) 65 { 66 tree[x].min_left = min(tree[x<<1].min_left,tree[x<<1|1].min_left); 67 } 68 69 void build(int x,int l,int r) 70 { 71 tree[x].l=l,tree[x].r=r; 72 if(l==r) 73 { 74 tree[x].min_left = -1; 75 } 76 else 77 { 78 int mid = (l+r)/2; 79 build(x<<1,l,mid); 80 build(x<<1|1,mid+1,r); 81 push_up(x); 82 } 83 } 84 void update_tree(int x, int l, int r, int pos, int value) { 85 if(l>r || l>pos || r<pos) return; 86 if(l==r) 87 { 88 tree[x].update(value); 89 } 90 else 91 { 92 int mid = (l+r)/2; 93 if(pos<=mid)update_tree(x<<1,l,mid,pos,value); 94 if(pos<=r)update_tree(x<<1|1,mid+1,r,pos,value); 95 push_up(x); 96 } 97 } 98 99 int query_tree(int x, int l, int r, int value) { 100 if(l==r) return l; 101 int mid = (l+r)/2; 102 if(tree[x<<1].min_left<value) return query_tree(x<<1,l,mid,value); 103 else return query_tree(x<<1|1,mid+1,r,value); 104 } 105 106 int main() { 107 int i; 108 scanf("%d", &n); 109 for(i=1;i<=n;i++) 110 { 111 scanf("%d", &a[i]); 112 } 113 build(1,1,1000003); 114 for(i=1;i<=n;i++) 115 { 116 if(i==1)update_tree(1,1,1000003,1,1); 117 else update_tree(1,1,1000003,ans[i],i); 118 int l=i-a[i]+1; 119 ans[i+1]=query_tree(1,1,1000003,l); 120 } 121 for(i=2;i<=n+1;i++) 122 if(i<n+1)printf("%d ", ans[i]); 123 else printf("%d\n", ans[i]); 124 125 return 0; 126 }
D - 一棵复杂的线段树
A[1...n]为1到n的一个全排列
对[L,R]区间,升序排序或降序排序
排完后查找第K个数
思路:线段树+二分答案
结果只要求a[k]的值,并且a数列是1-n的一个全排列,那么可以二分答案。
排序过程不好想,假设mid为答案,将>mid的设为1,<=mid的设为0。
当对 [L,R] 区间进行排序时,
1. 先求出区间内1的个数。
2. 区间全置为0.
3. 升序排序时,将最后c个数 ( [R-c+1, R] ) 置为1.
4. 降序排序时,将前c个数( [L, L + c - 1] )置为1.
所有操作进行结束后,如果 [k, k] == 1 说明 a[k] > mid ( li = mid + 1 ) , 为 0 说明 a[k] <= mid ( ri = mid ) 。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int AX = 1e5+66; 4 int lazy[AX<<2]; 5 int s[AX<<2]; 6 int a[AX]; 7 int op[AX]; 8 int l[AX]; 9 int r[AX]; 10 int n,k; 11 int tot; 12 13 void push_down( int rt , int l , int r ){ 14 if( lazy[rt] != -1 ){ 15 int mid = ( l + r ) >> 1 ; 16 s[rt<<1] = ( mid - l + 1 ) * lazy[rt] ; 17 s[rt<<1|1] = ( r - mid ) * lazy[rt]; 18 lazy[rt<<1] = lazy[rt]; 19 lazy[rt<<1|1] = lazy[rt]; 20 lazy[rt] = -1; 21 } 22 return ; 23 } 24 25 26 void push_up( int rt ){ 27 s[rt] = s[rt<<1] + s[rt<<1|1]; 28 return ; 29 } 30 31 void build( int l , int r , int rt , int v ){ 32 lazy[rt] = -1; 33 if( l == r ){ 34 s[rt] = ( a[l] > v ) ; 35 return ; 36 } 37 int mid = ( l + r ) >> 1 ; 38 build( l , mid , rt << 1 , v ); 39 build( mid + 1 , r , rt << 1 | 1 , v); 40 push_up(rt); 41 } 42 43 void update( int L , int R , int v , int l , int r , int rt ){ 44 if( L <= l && r <= R ){ 45 s[rt] = v * ( r - l + 1 ); 46 lazy[rt] = v; 47 return; 48 } 49 push_down(rt,l,r); 50 int mid = ( l + r ) >> 1; 51 if( L <= mid ) update( L , R , v , l , mid , rt << 1 ); 52 if( R > mid ) update( L , R , v , mid + 1 , r , rt << 1 | 1); 53 push_up(rt); 54 } 55 56 int query( int L , int R , int l , int r , int rt ){ 57 if( L <= l && r <= R ){ 58 return s[rt]; 59 } 60 push_down(rt,l,r); 61 int ans = 0 ; 62 int mid = ( l + r ) >> 1; 63 if( L <= mid ) ans += query( L , R , l , mid, rt << 1 ); 64 if( R > mid ) ans += query( L , R , mid + 1, r , rt << 1 | 1 ); 65 return ans ; 66 } 67 68 int main(){ 69 scanf("%d%d",&n,&k); 70 for( int i = 1 ; i <= n ; i++ ){ 71 scanf("%d",&a[i]); 72 } 73 int m ; 74 scanf("%d",&m); 75 for( int i = 0 ; i < m ; i++ ){ 76 scanf("%d%d%d",&op[i],&l[i],&r[i]); 77 } 78 int li = 1 , ri = n ; 79 while( li < ri ){ // [li,ri] 80 int mid = ( li + ri ) >> 1 ; 81 build( 1 , n , 1 , mid ); 82 for( int i = 0 ; i < m ; i++ ){ 83 int L = l[i]; 84 int R = r[i]; 85 int c = query( L , R , 1 , n , 1 ); // 区间查询 > mid 的个数 86 update( L , R , 0 , 1 , n , 1 ); // 区间更新 为0 87 if( op[i] ){ 88 if( L <= L + c - 1 ){ 89 update( L , L + c - 1 , 1 , 1, n , 1 ); // 区间更新 90 } 91 }else{ 92 if( R - c + 1 <= R ){ 93 update( R - c + 1 , R , 1 , 1 , n , 1 ); // 区间更新 94 } 95 } 96 } 97 if( query( k , k , 1 , n , 1 )) li = mid + 1; // 单点查询 98 else ri = mid; 99 } 100 printf("%d\n",li); 101 return 0 ; 102 }
转载于:https://www.cnblogs.com/demian/p/9562808.html
2018 UESTC 线段树专题相关推荐
- 线段树专题-黑白棋盘 BZOJ-1453
线段树专题-黑白棋盘 题目来源 BZOJ−1453BZOJ-1453BZOJ−1453 题意 QQQ次操作 每次操作给出(x,y)(x,y)(x,y),将(x,y)(x,y)(x,y)个格子颜色取反 ...
- 线段树专题-等差子序列 BZOJ-2124
线段树专题-等差子序列 感谢 感谢孙耀峰的线段树PPT,使我获益匪浅. 题目来源 BZOJ−2124BZOJ-2124BZOJ−2124 题意 给出长度为nnn的1−n1-n1−n的排列AAA 问是否 ...
- 蒟蒻君的刷题日记Day12(线段树专题T4):P8082 [COCI2011-2012#4] KEKS 线段树版题解
解题思路 看题解区的大佬们用的都是单调栈,本蒟蒻献上一篇线段树题解. 整个数最大,首先位数是确定的,则肯定优先考虑高位大小. 大体思路就是从前向后依次求出每一位的值(好像是废话). 对于第 iii 位 ...
- [BZOJ5249][九省联考2018]IIIDX(线段树)
5249: [2018多省省队联测]IIIDX Time Limit: 40 Sec Memory Limit: 512 MB Submit: 32 Solved: 17 [Submit][Sta ...
- 线段树专题 A(单点更新)
#include <iostream> #include<cstdio> #include<cstring> using namespace std; const ...
- 【POJ 2482】 Stars in Your Window(线段树+离散化+扫描线)
[POJ 2482] Stars in Your Window(线段树+离散化+扫描线) Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...
- ACM之路(14)—— 线段树的日常(上)
我的线段树简直有毒,各种错误都能忙上半天.做了kuangbin的线段树专题的一半,还有一半留到以后去做. 链接:http://acm.hust.edu.cn/vjudge/contest/view.a ...
- HDU1255 覆盖的面积 (线段树 + 扫描线)
题目链接:覆盖的面积 大致题意 现在有平面直角坐标系xoy, 有n个平行于x轴y轴的矩形, 给出这些矩形的左上角和右下角的坐标, 让你求出这些矩形组成的图形中被至少两个矩形覆盖的部分的总面积. 解题思 ...
- HDU 4417 Super Mario(线段树||树状数组+离线操作 之线段树篇)
Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...
最新文章
- Android性能优化之提高ListView性能的技巧
- [BZOJ 2425] 计数
- angular select设置默认选中_技术分享 | Charset 和 Collat??ion 设置对 MySQL 性能的影响...
- keras从入门到放弃(十六)内置预训练网络VGG
- 统计字符串中单词个数
- 辽宁工业大学计算机复试经验,辽宁工业大学车辆工程考研经验
- Android中应用程序获得系统签名权限(platform.x509.pem platform.pk8)下载地址
- vue使用高德地图获取当前经纬度
- 如何隐藏C/C++编译生成的函数符号
- 410c 上安装中文版本的答题器游戏demo
- 获取当天的0点0分0秒的日期和23点59分59秒的日期
- es6+最佳入门实践(8)
- Java实现单向链表基本功能
- 【java当中摄像头调用保姆级别教程和在摄像头上实现滤镜效果】
- win下连编socket时[Linker error] undefined reference to XXX
- 物联网专科专业必修课程_物联网应用技术专业介绍(专科)
- 使用html+css完成仿站操作要点
- 深度之眼Paper带读笔记GNN.06.GAT
- 使用百度地图api根据网吧名称获取经纬度信息
- Redis 面试题!精华!收藏一波 !
热门文章
- java封装,继承和多态
- 二叉树求深度的递归的详细分析
- Java protect属性
- android menu点击事件6,Android Menu
- 网络营销外包专员浅析网站网络营销外包如何快速获取关键词排名
- mongodb java findone_java-MongoRepository findOne使用“ id”代替“ _id”
- android log4,GitHub - oronno/log4android: Log4Android - Simple Logging Wrapper Library for Android
- python3 读取csv
- 想实现高可用?先搞定负载均衡原理
- mysql 根据字段映射