洛谷 P3372 线段树1-分块做法 分块板子题

我向来不喜欢废话,直接开始说啦!

传送门:P3372 【模板】线段树 1

预处理:

①段数t=sqrt(n);

②每段左边界L[i]=(i-1)*t+1;

③每段右边界R[i]=i*t;

④补充处理:t2小于n的再补一段,左边界R[t-1]+1,右边界n;

⑤区间和sum[i]=∑jL[i]<=j<=R[i]a[j];

⑥预设增量标记add=0;

 

区间修改:

(情况一)l,r在同一块内:直接对区间内的每个数加,区间和用询问长度用修改1次;

(情况二)l,r不在同一块内:

①l+1到r-1块内:全部修改增量标记;

②l块:做法同情况1,右边界是R[pos[l]];

③r快:做法同情况1,左边界是L[pos[r]];

 

区间查询:

(情况一)l,r在同一块内:直接对区间内的数求和,再加上增量标记*询问长;

(情况二)l,r不在同一块内:

①l+1到r-1块内:全部加上区间和以及增量标记*段长;

②l块:做法同情况1,右边界是R[pos[l]];

③r快:做法同情况1,左边界是L[pos[r]];

 

整体思想:大段维护,(抱歉打错字啦)局部朴素

撒花!

 

 


 

 

 

 

 

 

 

 

 

 

真没了,回去吧

 

 

 

 

 

 

 

 

 

 

 

  1 //Written By Peter0701
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 int n,m,t,l,r,k,op;
  5 int L[100005],R[100005],pos[100005];
  6 long long sum[100005],add[100005],a[100005];
  7 inline int read()
  8 {
  9     int ret=0,f=1;
 10     char ch=getchar();
 11     while(ch>'9'||ch<'0')
 12     {
 13         if(ch=='-') f=-1;
 14         ch=getchar();
 15     }
 16     while(ch>='0'&&ch<='9')
 17     {
 18         ret=(ret<<1)+(ret<<3)+ch-'0';
 19         ch=getchar();
 20     }
 21     return ret*f;
 22 }
 23 void change(int l,int r,int d)
 24 {
 25     int p=pos[l],q=pos[r];
 26     if(p==q)
 27     {
 28         for(register int i=l;i<=r;i++)
 29             a[i]+=d;
 30         sum[p]+=d*(r-l+1);
 31     }
 32     else
 33     {
 34         for(register int i=p+1;i<=q-1;i++)
 35             add[i]+=d;
 36         for(register int i=l;i<=R[p];i++)
 37             a[i]+=d;
 38         sum[p]+=d*(R[p]-l+1);
 39         for(register int i=L[q];i<=r;i++)
 40             a[i]+=d;
 41         sum[q]+=d*(r-L[q]+1);
 42     }
 43 }
 44 long long ask(int l,int r)
 45 {
 46     int p=pos[l],q=pos[r];
 47     long long ans=0;
 48     if(p==q)
 49     {
 50         for(register int i=l;i<=r;i++)
 51             ans+=a[i];
 52         ans+=add[p]*(r-l+1);
 53     }
 54     else
 55     {
 56         for(register int i=p+1;i<=q-1;i++)
 57             ans+=sum[i]+add[i]*(R[i]-L[i]+1);
 58         for(register int i=l;i<=R[p];i++)
 59             ans+=a[i];
 60         ans+=add[p]*(R[p]-l+1);
 61         for(register int i=L[q];i<=r;i++)
 62             ans+=a[i];
 63         ans+=add[q]*(r-L[q]+1);
 64     }
 65     return ans;
 66 }
 67 int main()
 68 {
 69     n=read();
 70     m=read();
 71     for(register int i=1;i<=n;i++)
 72         a[i]=read();
 73     t=sqrt(n);
 74     for(register int i=1;i<=t;i++)
 75     {
 76         L[i]=(i-1)*t+1;
 77         R[i]=i*t;
 78     }
 79     if(R[t]<n)
 80         t++,L[t]=R[t-1]+1,R[t]=n;
 81     for(register int i=1;i<=t;i++)
 82     {
 83         for(register int j=L[i];j<=R[i];j++)
 84         {
 85             pos[j]=i;
 86             sum[i]+=a[j];
 87         }
 88     }
 89     while(m--)
 90     {
 91         op=read();
 92         l=read();
 93         r=read();
 94         if(op==1)
 95         {
 96             k=read();
 97             change(l,r,k);
 98         }
 99         else
100         {
101             printf("%lld\n",ask(l,r));
102         }
103     }
104     return 0;
105 }
说了没了你还来,这下被发现了吧

转载于:https://www.cnblogs.com/Peter0701/p/10048728.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值