1.相关时间复杂度:
因为总结点个数为2n,因此:
初始化:O(n)
因为不论哪种操作,对于每个深度都最多访问常数个结点,因此:
每次更新:O(logn)
每次求值:O(logn)
2.线段树结构:
线段树结点下标和元素范围下标均从1记。那么:
每个结点存着[l,r]范围内的值。
第1个结点维护[1,n]范围的值。
每个结点k的左右叶子结点下标分别为k<<1,k<<1|1。
然而初始数组的下标是从0记的,所以在build的时候,c[k].sum=s[l-1]。
c[i].l和c[i].r记录了该结点维护的元素的范围下标。
维护区间和板子(单点更新,区间查询)。
public class Main {
static InputReader sc=new InputReader(System.in);
static PrintWriter out=new PrintWriter(System.out);
static int mod=1000000007,n,maxn=100010,INF=1000000000;
static SegmentTree t=new SegmentTree();
static char s[];
static class tnode{
int l,r;
long sum;
}
static class SegmentTree{
tnode c[]=new tnode[maxn*4];
SegmentTree() {
for(int i=0;i<4*maxn;i++) {
c[i]=new tnode();
}
}
void build(int l,int r,int k) {
//tnode存了其维护的区间.所以只在build中需要lr参数,update query不需要。
c[k].l=l;
c[k].r=r;
c[k].sum=0;
if(l==r) {
c[k].sum=s[l-1];
return;
}
int mid=(l+r)/2;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
c[k].sum=c[k<<1].sum+c[k<<1|1].sum;
c[k].sum=(c[k].sum+mod)%mod;
}
void update(int ind,int k,int p) {
//ind为原数组中第Ind,k为当前所在线段树结点的下标,p为修改后的值
if(c[k].l==c[k].r) {
c[k].sum=p;
return;
}
int mid=c[k].l+c[k].r;
mid/=2;
if(ind<=mid) update(ind,k<<1,p);
else update(ind,k<<1|1,p);
c[k].sum=c[k<<1].sum+c[k<<1|1].sum;
c[k].sum=(c[k].sum+mod)%mod;
}
int query(int a,int b,int k) {//查询的区间[a,b],线段树结点下标k
if(c[k].l>=a&&c[k].r<=b) {
return c[k].val;
}
int mid=c[k].l+c[k].r;
mid/=2;
int L=0,R=0;
if(a<=mid)L=query(a,b,k<<1);
if(b>mid)R=query(a,b,k<<1|1);
return L+R;
}
}
public static void main(String args[]) {
n=sc.nextInt();
s=sc.nextLine().toCharArray();
t.build(1, n, 1);
}
}
结点维护其区间的和,区间更新区间查询,旧lazytag的更新只在查询时操作,更新函数只负责将lazytag累加和更新对应结点的值并pushup.(这个没写pushup pushdown函数,可以写= =)
注:lazytag只在区间更新中有意义,单点更新不需要lazytag
public class C {
public static int INF=(1<<30)-1,maxn=100100,n;
public static long arr[]=new long[maxn*4],tree[]=new long[maxn*4],add[]=new long[maxn*4];
public static long build(int l,int r,int rt) {
if(l==r) {
tree[rt]=arr[l];
return tree[rt];
}
int mid=(l+r)/2;
long L=build(l,mid,2*rt);
long R=build(mid+1,r,2*rt+1);
tree[rt]=L+R;
return tree[rt];
}
public static long update(int a,int b,int k,int l,int r,int rt) {
if(a<=l&&b>=r) {
add[rt]+=k;
return (r-l+1)*k;
}
int mid=(l+r)/2;
int ans=0;
if(a<=mid) {
ans+=update(a,b,k,l,mid,rt*2);
}
if(b>=mid+1) {
ans+=update(a,b,k,mid+1,r,rt*2+1);
}
tree[rt]+=ans;
return ans;
}
public static long query(int a,int b,int l,int r,int rt) {
tree[rt]+=(r-l+1)*add[rt];
if(l!=r){
add[rt*2]+=add[rt];
add[rt*2+1]+=add[rt];
}
add[rt]=0;
if(a<=l&&b>=r) {
return tree[rt];
}
int mid=(l+r)/2;
long ans=0;
if(a<=mid) {
ans+=query(a,b,l,mid,2*rt);
}
if(b>=mid+1) {
ans+=query(a,b,mid+1,r,2*rt+1);
}
return ans;
}
public static InputReader sc=new InputReader(System.in);
public static void main(String args[]) {
n=sc.nextInt();
int N=n;
n=1;
while(n<N) {
n*=2;
}
int q=sc.nextInt();
for(int i=1;i<=N;i++) {
arr[i]=sc.nextLong();
//System.out.println(arr[i]);
}
build(1,n,1);
while(q-->0) {
String str;
str=sc.readString();
if(str.charAt(0)=='Q') {
int l=sc.nextInt();
int r=sc.nextInt();
System.out.println(query(l, r, 1, n, 1));
}else {
int l=sc.nextInt();
int r=sc.nextInt();
int c=sc.nextInt();
update(l, r, c, 1, n, 1);
}
}
}
}