洛谷P3372 【模板】线段树 1

版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82809661

链接

https://www.luogu.org/problemnew/show/P3372


大意

给定一个序列,要求支持区间修改和区间查询


思路

线段树啊。。。
(然而跑得比分块还慢。。。)
于是就码了个分块
然后https://www.luogu.org/recordnew/lists?uid=52915&pid=P3372


最后才发现++t放出来就A了!
就A了!
就A了!
就A了!!!!


线段树代码

#include<cstdio>
#include<iostream>
#define lson (k<<1)
#define rson (k<<1|1)
#define mid ((a+b)>>1)
#define LL long long
#define IL inline
using namespace std;
struct node
{
    LL l,r,num,lazy;
}tree[400001];//线段树数组
LL n,c[100001],ans,m,x,y,z,k,L=1;
LL slazy(LL k){return (tree[k].r-tree[k].l+1)*tree[k].lazy;}//计算lazy值
IL LL read()//读入优化
{
    int d=1;LL f=0;char c;
    while(c=getchar(),c<=47||c>=58) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
IL void write(LL x)//输出优化
{
    if(x<0) {x=-x;putchar('-');}
    if(x>9) write(x/10);putchar(x%10+48);
    return;
}
void build2()//非递归构造法(较快)
{
    while(L<n) L<<=1;
    for(LL i = 1; i <= n; i++) 
        tree[i+L-1].l=tree[i+L-1].r=i,tree[i+L-1].num=c[i];
    for(LL i=L+n;i<L<<1;i++)
        tree[i].l=tree[i].r=i-L+1;
    for(LL i=L-1;i>=1;i--)
        tree[i].l=tree[i<<1].l,
        tree[i].r=tree[i<<1|1].r,
        tree[i].num+=tree[i<<1].num+tree[i<<1].num;
}
void build(LL k,LL a,LL b)//递归构造法(较慢)注意这里没有处理num
{
    tree[k].l=a;
    tree[k].r=b;
    if(a==b) return;
    build(lson,a,mid);build(rson,mid+1,b);
}
IL LL add(LL k)//构造num
{
    if(tree[k].l==tree[k].r) return tree[k].num=c[tree[k].r];
    return tree[k].num=add(lson)+add(rson);
}
IL void push(LL k)//下传lazy标记
{
    if(!tree[k].lazy) return;
    tree[lson].lazy+=tree[k].lazy;
    tree[rson].lazy+=tree[k].lazy;
    tree[k].num+=slazy(k);
    tree[k].lazy=0;
}
IL void updata(LL k,LL a,LL b,LL x)//区间修改
{
    if(tree[k].l==a&&tree[k].r==b)
    {
        tree[k].lazy+=x;
        return;
    }
    push(k);//记得下传
    if(tree[lson].r>=b) updata(lson,a,b,x);else
    if(tree[rson].l<=a) updata(rson,a,b,x);else
    {
        updata(lson,a,tree[lson].r,x);
        updata(rson,tree[rson].l,b,x);
    }
    tree[k].num=tree[lson].num+tree[rson].num+slazy(lson)+slazy(rson);//维护
}
IL LL find(LL k,LL a,LL b)
{
    if(tree[k].l==a&&tree[k].r==b)
     return tree[k].num+slazy(k);//到达则返回
    push(k);//下传
    if(tree[lson].r>=b) return find(lson,a,b);else
    if(tree[rson].l<=a) return find(rson,a,b);else
    return find(lson,a,tree[lson].r)+find(rson,tree[rson].l,b);//分情况讨论
}
signed main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) c[i]=read();//输入
    build(1,1,n);
    add(1);//这两行可以合起来即为build2
    while(m--)
    {
    	k=read();
        if(k==1)
        {
        	x=read();y=read();z=read();
        	updata(1,x,y,z);
        }
        else
        {
        	x=read();y=read();
        	write(find(1,x,y));putchar(10);
        }
    }
}

分块代码

#include<cstdio>
#include<iostream>
#include<cmath>
#define IL inline
#define LL long long 
#define r(i,a,b) for(register int i=a;i<=b;i++)
#define N 100010
using namespace std;
LL a[N],sum[N],add[N],ans;
LL L[N],R[N],Pos[N],n,m,x,y,z;
int t;
char c;
IL void change(LL l,LL r,LL d)//区间修改
{
    LL p=Pos[l],q=Pos[r];
    if(p==q) {r(i,l,r) a[i]+=d,sum[p]+=d;return;}
    r(i,p+1,q-1) add[i]+=d;
    r(i,l,R[p]) a[i]+=d,sum[p]+=d;
    r(i,L[q],r) a[i]+=d,sum[q]+=d;
    return;
}
IL LL ask(LL l,LL r)//区间查询
{
    LL p=Pos[l],q=Pos[r];
    LL ans=0;
    if(p==q)//在同一块内
    {
        r(i,l,r) ans+=a[i]+add[p];
    }
    else//否则
    {
        r(i,p+1,q-1) ans+=sum[i]+add[i]*(R[i]-L[i]+1);
        r(i,l,R[p]) ans+=a[i]+add[p];
        r(i,L[q],r) ans+=a[i]+add[q];
    }
    return ans;
}
IL LL read()//输入优化
{
    int d=1;LL f=0;char c;
    while(c=getchar(),c<=47||c>=58) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
IL void write(LL x)//输出优化
{
    if(x<0) {x=-x;putchar('-');}
    if(x>9) write(x/10);putchar(x%10+48);
    return;
}
signed main()
{
    n=read();m=read();
    r(i,1,n) a[i]=read();
    t=(int)sqrt((double)n);
    r(i,1,t) L[i]=(i-1)*t+1,R[i]=i*t;
    if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;//超级坑点
    r(i,1,t) r(j,L[i],R[i]) Pos[j]=i,sum[i]+=a[j];
    while(m--)
    {
        while(c=getchar(),c!='2'&&c!='1');
        if(c=='2') 
        {
            x=read();y=read();
            ans=ask(x,y);
            write(ans);
            putchar(10);
        }
        else 
        {
            x=read();y=read();z=read();
            change(x,y,z);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/82809661