suoi37 清点更多船只 (卡空间线段树)

sbw巨佬的卡空间方法,把线段树的叶节点只记到长度为16的区间,然后在叶节点上暴力修改查询,这样点数是$\frac{N}{8}$的,可以过...

orz

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxn=(1<<20),maxp=(1<<18)+10;
  7 
  8 inline ll rd(){
  9     ll x=0;char c=getchar();int neg=1;
 10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 12     return x*neg;
 13 }
 14 
 15 ll sum[maxp],v[maxn],laz[maxp];
 16 int N,M;
 17 
 18 inline void update(int p,int l,int r){
 19     if(r-l+1<=16){    
 20         sum[p]=0;
 21         for(int i=l;i<=r;i++){
 22             sum[p]+=v[i];
 23         }
 24     }else{
 25         sum[p]=sum[p<<1]+sum[p<<1|1];
 26     }
 27 }
 28 inline void deal(int p,int l,int r,ll z){
 29     if(r-l+1<=16){
 30         for(int i=l;i<=r;i++){
 31             v[i]+=z,sum[p]+=z;
 32         }
 33     }else sum[p]+=z*(r-l+1);
 34 }
 35 
 36 inline void pushdown(int p,int l,int r){
 37     if(!laz[p]||r-l+1<=16) return;
 38     int a=p<<1,b=p<<1|1,m=l+r>>1;
 39     deal(a,l,m,laz[p]),deal(b,m+1,r,laz[p]);
 40     laz[a]+=laz[p],laz[b]+=laz[p];
 41     laz[p]=0;
 42 }
 43 
 44 void build(int p,int l,int r){
 45     if(r-l+1<=16) update(p,l,r);
 46     else{
 47         int m=l+r>>1;
 48         build(p<<1,l,m);
 49         build(p<<1|1,m+1,r);
 50         // printf("!%d %d %d\n",p,l,r);
 51         update(p,l,r);
 52     }
 53 }
 54 
 55 ll query(int p,int l,int r,int x,int y){
 56     // printf("~~%d %d %d %d %d\n",p,l,r,x,y);
 57     pushdown(p,l,r);
 58     if(x<=l&&r<=y) return sum[p];
 59     if(r-l+1<=16){
 60         ll re=0;
 61         for(int i=x;i<=y;i++) re+=v[i];
 62         return re;
 63     }
 64     int m=l+r>>1;ll re=0;
 65     if(x<=m) re=query(p<<1,l,m,x,min(m,y));
 66     if(y>=m+1) re+=query(p<<1|1,m+1,r,max(x,m+1),y);
 67     return re;
 68 }
 69 
 70 void add(int p,int l,int r,int x,int y,ll z){
 71     // printf("!!%d %d %d %d %d\n",p,l,r,x,y);
 72     pushdown(p,l,r);
 73     if(r-l+1<=16){
 74         for(int i=x;i<=y;i++)
 75             v[i]+=z,sum[p]+=z;
 76     }else if(x<=l&&r<=y){
 77         deal(p,l,r,z);
 78         laz[p]+=z;
 79     }else{
 80         int m=l+r>>1;
 81         if(x<=m) add(p<<1,l,m,x,min(m,y),z);
 82         if(y>=m+1) add(p<<1|1,m+1,r,max(m+1,x),y,z);
 83         update(p,l,r);
 84     }
 85 }
 86 
 87 int main(){
 88     //freopen("","r",stdin);
 89     int i;
 90     N=rd(),M=rd();
 91     for(i=1;i<=N;i++)
 92         v[i]=rd();
 93     N=1<<((int)log2(N)+1);
 94     build(1,1,N);
 95     for(i=1;i<=M;i++){
 96         char s[10];
 97         scanf("%s",s);
 98         int l=rd(),r=rd();
 99         if(s[1]=='d'){
100             int d=rd();
101             add(1,1,N,l,r,d);
102         }else printf("%lld\n",query(1,1,N,l,r));
103     }
104     return 0;
105 }

 

转载于:https://www.cnblogs.com/Ressed/p/9794670.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值