hiho #1078 : 线段树的区间修改

题意:长度为n的序列上有两种操作

0 ql qr  输出区间[ql,qr]和

1 ql qr v 区间[ql,qr]赋值为v

线段树懒标基础题,我用分块写了一个,在本题数据竟然跑的飞快

#include<iostream>
#include<cstdio>
#include<cmath>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1e5+5;
typedef long long ll;

int val[maxn],belong[maxn],l[maxn],r[maxn],inv[maxn];
ll ans[maxn];
int n,q,op,ql,qr,v,cnt,block;

void update(int L,int R,int bt){
    if(L==l[bt]&&R==r[bt]){
	inv[bt]=v;ans[bt]=(ll)v*(R-L+1);
	return ;
    }
    if(inv[bt]){
      rep(i,l[bt],L-1)val[i]=inv[bt];
      rep(i,R+1,r[bt])val[i]=inv[bt];
      rep(i,L,R)ans[bt]+=v-inv[bt],val[i]=v;
      inv[bt]=0;
      return ;
    }
    rep(i,L,R)ans[bt]+=v-val[i],val[i]=v;
}

void update(){
    int b1=belong[ql],b2=belong[qr];
    if(b1==b2)update(ql,qr,b1);
    else{
	update(ql,r[b1],b1);b1++;
	while(b1<b2)
	  update(l[b1],r[b1],b1),b1++;
	update(l[b2],qr,b2);
    }
}

ll query(int L,int R,int bt){
    if(l[bt]==L&&r[bt]==R)return ans[bt];
    if(inv[bt])return (ll)inv[bt]*(R-L+1);
    ll res=0;
    rep(i,L,R)res+=val[i];
    return res;
}

ll query(){
    ll res=0;
    int b1=belong[ql],b2=belong[qr];
    if(b1==b2)return query(ql,qr,b1);
    res+=query(ql,r[b1],b1);b1++;
    while(b1<b2)res+=ans[b1++];
    res+=query(l[b2],qr,b2);
    return res;
}

void init(){
    block=sqrt(n);cnt=n/block;
    rep(i,0,n-1){
	belong[i]=i/block;
	ans[belong[i]]+=val[i];
    }
    rep(i,0,cnt-1)l[i]=i*block,r[i]=(i+1)*block-1;
    if(n%block){
	l[cnt]=cnt*block,r[cnt]=n-1;cnt++;
    }
}

int main(){
    scanf("%d",&n);
    rep(i,0,n-1)scanf("%d",val+i);
    init();
    scanf("%d",&q);
    while(q--){
	scanf("%d%d%d",&op,&ql,&qr);
	ql--;qr--;
	if(op){
	    scanf("%d",&v);
	    update();
	}
	else
	    printf("%lld
",query());
    }
  
    return 0;
}
原文地址:https://www.cnblogs.com/jihe/p/6945108.html