线段树
2017-01-21 20:25
225 查看
线段树
线段树可用于查询修改各种区间问题,它在信息学竞赛中的使用无比广泛,从普及到 CTSC 到处都有它的身影。模板
[Luogu3372]【模板】线段树 1
已知一个数列,你需要进行下面两种操作:将某区间每一个数加上x;
求出某区间每一个数的和.
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> const int MAXN=1e5+5,MAXM=1e5+5; typedef long long ll; int n,m; ll na[MAXN]; const int rt=1; struct SEGTN{int l,r,lc,rc;ll sum,tag;} t[MAXN<<1];int tcnt=rt; void upd(int o){t[o].sum=t[t[o].lc].sum+t[t[o].rc].sum;} void pushdown(int o) { int lc=t[o].lc,rc=t[o].rc; if(t[o].tag) { t[lc].tag+=t[o].tag;t[lc].sum+=(t[lc].r-t[lc].l+1)*t[o].tag; t[rc].tag+=t[o].tag;t[rc].sum+=(t[rc].r-t[rc].l+1)*t[o].tag; t[o].tag=0; } } void buildTree(int o,int l,int r) { t[o].l=l,t[o].r=r; if(l==r) { t[o].sum=na[l];return; } int mid=(l+r)>>1; t[o].lc=++tcnt;buildTree(t[o].lc,l,mid); t[o].rc=++tcnt;buildTree(t[o].rc,mid+1,r); upd(o); } void chDet(int o,int l,int r,ll v) { if(l<=t[o].l&&t[o].r<=r) { t[o].tag+=v,t[o].sum+=(t[o].r-t[o].l+1)*v; return; } pushdown(o); int mid=(t[o].l+t[o].r)>>1; if(l<=mid) chDet(t[o].lc,l,r,v); if(r>mid) chDet(t[o].rc,l,r,v); upd(o); } ll calSum(int o,int l,int r) { if(l<=t[o].l&&t[o].r<=r) return t[o].sum; int mid=(t[o].l+t[o].r)>>1; pushdown(o); ll res=0; if(l<=mid) res+=calSum(t[o].lc,l,r); if(r>mid) res+=calSum(t[o].rc,l,r); return res; } int main() { int i; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&na[i]); buildTree(rt,1,n); while(m--) { int opt,x,y;scanf("%d%d%d",&opt,&x,&y); if(opt==1) { ll z;scanf("%lld",&z); chDet(rt,x,y,z); }else printf("%lld\n",calSum(rt,x,y)); } }
拓展应用
区间取模
由于一个数取模一次其大小最大是原来的 12 ,所以一直对一个数 n 取模的话最多只需 log2n 次就会被模成 0.那我们维护区间最大值,对区间取模时判断区间最大值是否小于要模的值。若是,则不用操作,否则暴力更新即可。
[ZOJ3886]Nico Number
如果正整数 x 满足不大于 x 且与 x 互质的数能组成一个等差数列,那么我们称 x 为 Niconico 数。现在给出一个长度 N 的数列,有如下 T 个操作:
统计一个区间内 Niconico 数的个数;
区间取模;
单点修改。
N,T≤105,操作过程中数列中的数及取模的数≤107
其实这道题的难点是 Niconico 数
Niconico 数一定是:质数或 2k 或 6.
神奇的标记
[2017.07.18] 心理学概论
给定 N 个三元组 (xi,yi,zi) ,现在有三个集合 X,Y,Z ,每个三元组可以取 xi,yi,zi 中的任意一个值并将这个值并放入对应的 X,Y,Z 集合中,求这三个集合中元素的最大值之和的最小值。N≤105,1≤xi,yi,zi≤108
首先我们考虑二元组的情况,我们可以先将二元组按照 xi 的升序排序,然后我们可以枚举一个位置 p ,取 xi,i∈[1,p] 和 yj,j∈[p+1,N] ,由于 xp 是选中的 x 中最大的,这样答案就是 xp+Max{yi,i∈[p+1,N]}
那么我们考虑三元组的情况,我们第一想法就是将三元组再按 yi 的升序排序,然后再枚举一遍,这样时间复杂度就是 O(N2) ,只能通过 50% 的数据。
那么我们能优化的就是枚举第二个边界的时间复杂度了。
相关文章推荐
- OpenWrt 中安装配置Transmission
- python应用 (1) 解析xml
- iOS动画案例(1) 类似于qq账号信息里的一个动画
- 【设计模式】--代理模式 (Proxy模式)
- 【清明】并查集
- struts基本概念(2)
- More Effective C++学习笔记(4)-效率
- C#与C++在语法上的区别
- HTML5移动端手机网站开发流程
- 12 共享内存2
- 最近的一些事情
- 用memset设置无穷大无穷小
- SPOJ Count on a tree(lca+主席树,树上主席树,好题)
- struts基本概念(1)
- python使用@property
- 【WC模拟】J
- 藏宝图
- RunTimeException 在Java中的异常处理
- mybatis
- ubuntu16.04安装jekyll 3.3.1