• 题解 P3372 【【模板】线段树 1】


    发一篇不需要O2就能过的分块。

    基本思路:

    分块的思路,大段维护,小段朴素。

    维护几个数组:

    • 区块(block[maxn])
    • 懒标记(tag[maxn])
    • 真实数据(data[maxn])

    更新时

    假设我们涉及到的区块的编号区间是([lb,rb])真实数据范围为([l,r])

    那么,我们在区块([lb+1,rb-1])区间,给(block[i])加上(Delta k) 并且打上懒标记 (=Delta k)。在真实数据的([l,lb imes N])([rb imes N-N+1,r])区间的每个(data[i])加上(Delta k)

    查询时

    同样的,对于区块区间([lb+1,rb-1])直接累加就好,对于(l b)区间和(rb)区间单独处理即可。

    上丑陋无比的代码。注意特判(l)(r)在一个区块区间的情况。

    #include<bits/stdc++.h>
    using namespace std;
    template< class ccf >inline ccf qr(ccf a) {
        char c=getchar();
        ccf x=0;
        int q=1;
        while(c<48||c>57)
    	q=c==45?-1:q,c=getchar();
        while(c>=48&&c<=57)
    	x=x*10+c-48,c=getchar();
        return q==-1?-x:x;
    }
    const int maxn=100055;
    typedef long long ll;
    ll data[maxn];
    ll tag[maxn];
    ll blk[maxn];
    int n;
    int m;
    int N;
    int adj;
    #define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;t++)
    int t1,t2;
    ll t3;
    int temp;
    
    void add(int l,int r,ll k) {
        int lb=(l+N-1)/N;
        int rb=(r+N-1)/N;
        if(lb!=rb) {
    
    	RP(t,l,N*lb)
    	    data[t]+=k,blk[lb]+=k;
    	RP(t,N*rb-N+1,r)
    	    data[t]+=k,blk[rb]+=k;
    	RP(t,lb+1,rb-1)
    	    tag[t]+=k,blk[t]+=N*k;
        } else
    	RP(t,l,r)
    	    data[t]+=k,blk[t]+=k;
    }
    
    ll sum(int l,int r) {
        ll ret=0;
        int lb=(l+N-1)/N;
        int rb=(r+N-1)/N;
        RP(t,lb+1,rb-1)
    	ret+=blk[t];
        if(tag[lb])
    	RP(t,N*lb-N+1,N*lb)
    	    data[t]+=tag[lb];
        tag[lb]=0;
        if(tag[rb])
    	RP(t,N*rb-N+1,min(N*rb,n))
    	    data[t]+=tag[rb];
        tag[rb]=0;
        if(lb!=rb) {
    	RP(t,l,N*lb)
    	    ret+=data[t];
    	RP(t,N*rb-N+1,r)
    	    ret+=data[t];
        } else
    	RP(t,l,r)
    	    ret+=data[t];
        return ret;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
        freopen("out.out","w",stdout);
    #endif
        n=qr(1);
        m=qr(1);
        RP(t,1,n)
    	data[t]=qr(1ll);
        N=sqrt(n);
        RP(t,1,n/N)
    	RP(i,1,N)
    	blk[t]+=data[(t-1)*N+i];
        RP(t,1,n%N)
    	blk[n/N+1]+=data[(n/N)*N+t];
        RP(t,1,m) {
    	temp=qr(1);
    	if(temp==1) {
    	    t1=qr(1);
    	    t2=qr(1);
    	    t3=qr(1ll);
    	    add(t1,t2,t3);
    	} else {
    	    t1=qr(1);
    	    t2=qr(1);
    	    printf("%ld
    ",sum(t1,t2));
    	}
        }
        return 0;
    }
    
    
  • 相关阅读:
    固定sql语句传参批量查询数据库脚本
    超多行数据纵向编辑
    takes 3 positional arguments but 4 were given错误
    使用PMD进行代码审查(转)
    WebADI应用到Office 2016 64-bit
    SVN 提交代码时强制加入注释内容
    DOCKER初体验
    "make_path" is not exported by the File::Path modul
    perl 调用shell脚本
    scp 上传文件到多个服务器节点
  • 原文地址:https://www.cnblogs.com/winlere/p/10308076.html
Copyright © 2020-2023  润新知