参考博客:线段树详解
线段树入门&lazy思想
板子:
//线段树模板(单点更新) #define Mid ((l+r)>>1) #define lson rt<<1,l,Mid #define rson rt<<1|1,Mid+1,r const int maxn = 100010; int sum[maxn<<2]; void build(int rt,int l,int r) { if(l==r){ scanf("%d",&sum[rt]); }else{ build(lson); build(rson); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } } void update(int rt,int l,int r,int pos,int num) //修改pos位值为num { if(l == r && r == pos){ sum[rt] += num; }else{ if( pos <= Mid) update(lson,pos,num); else update(rson,pos,num); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } } int query(int rt,int l,int r,int L,int R) //查询[L,R] { if(L <= l && r <= R){ return sum[rt]; }else{ int tmp = 0; if( L <= Mid) tmp += query(lson,L,R); if( R > Mid) tmp += query(rson,L,R); return tmp; } }
//线段树模板(区间更新) #define Mid ((l+r)>>1) #define lson rt<<1,l,Mid #define rson rt<<1|1,Mid+1,r const int maxn = 100010; int sum[maxn<<2],add[maxn<<2]; void build(int rt,int l,int r) { add[rt] = 0; if(l == r){ scanf("%d",&sum[rt]); //省个数组 }else{ build(lson); build(rson); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } } void pushDown(int rt,int len) { add[rt<<1] = add[rt<<1|1] = add[rt]; sum[rt<<1] = (len-(len>>1))*add[rt]; sum[rt<<1|1] = (len>>1)*add[rt]; add[rt] = 0; } void update(int rt,int l,int r,int L,int R,int z) //更新[L,R]为z { if(L <= l && r <= R){ add[rt] = z; sum[rt] = (r-l+1)*z; }else{ if(add[rt]) pushDown(rt,r-l+1); if(L <= Mid) update(lson,L,R,z); if(R > Mid) update(rson,L,R,z); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } } int query(int rt,int l,int r,int L,int R) //查询[L,R],调用:(1,1,n,L,R) { if(L <= l && r <= R){ return sum[rt]; }else{ if(add[rt]) pushDown(rt,r-l+1); int t = 0; if(L <= Mid) t += query(lson,L,R); if(R > Mid) t += query(rson,L,R); return t; } }
//建树 Build(1,n,1); //点修改 Update(L,C,1,n,1); //区间修改 Update(L,R,C,1,n,1); //区间查询 int ANS=Query(L,R,1,n,1);
模板题:
敌兵布阵 单点增减,区间求和。
通过代码:

/*输入 t样例 N(N<=50000) 第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。 接下来每行有一条命令,命令有4种形式: (1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30) (2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30); (3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数; (4)End 表示结束,这条命令在每组数据最后出现; 1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End 输出 Case 1: 6 33 59 */ #include#include <string> using namespace std; //线段树模板(单点更新) #define Mid ((l+r)>>1) // l+r/2; #define lson rt<<1,l,Mid //2*rt,l,mid, #define rson rt<<1|1,Mid+1,r //2*rt+1 ,mid+1,r; const int maxn = 100010; int sum[maxn<<2]; void build(int rt,int l,int r) { if(l==r) { scanf("%d",&sum[rt]); } else { build(lson); build(rson); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } } void update(int rt,int l,int r,int pos,int num,string c) //修改pos位 值为num { if(l == r && r == pos){ if(c == "Add") sum[rt] += num; if(c == "Sub") sum[rt] -= num; } else{ if( pos <= Mid) update(lson,pos,num,c); else update(rson,pos,num,c); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } } int query(int rt,int l,int r,int L,int R) //查询[L,R] { if(L <= l && r <= R){ return sum[rt]; } else{ int tmp = 0; if( L <= Mid) tmp += query(lson,L,R); if( R > Mid) tmp += query(rson,L,R); return tmp; } } int main() { int t,n,g=0,a,b; string c; cin>>t; while(t--) { g+=1;//case:g cin>>n; build(1,1,n); cout<<"Case "< ":"<<endl; while(cin>>c) { if(c=="End") break; cin>>a>>b; if(c=="Sub") update(1,1,n,a,b, "Sub"); if(c=="Add") update(1,1,n,a,b, "Add"); if(c=="Query") cout< 1,1,n,a,b)<<endl; } } }
算法作业的题目:
C时间限制:3000 毫秒 | C内存限制:3000 Kb
题目内容:
由10^7块1x1的玻璃构成1x10^7的海报墙,每个海报完整地覆盖几块玻璃,海报的宽度可以不同。后来的人可以覆盖 前人的海报。一张海报如果有没被覆盖的部分,则称为可视海报。你的任务是找出有多少可视海报。
输入:
第一行是测试的总数c,接下来的行是各测试用例。 每个测试的第一行是海报的总数n, n<=10000, 然后是n个按先后顺序贴的海报的位置li, ri. 满足1<=li<=ri<=10^7。
输出描述
每个测试的可视海报数目
输入样例
1 5 1 4 2 6 8 10 3 4 7 10
输出样例
4