SUOI #37 清点更多船只
经典问题
正常解法是树状数组或线段树
但这题内存给的很小
分块可以省内存
我们分析一下
树状数组 | 线段树 | 分块 | |
时间 | $NlogN=20\times 10^6$ | $NlogN=20\times 10^6$ | $N\sqrt N=10^3\times 10^6$ |
内存 | $2\times N=2\times 8\times 10^6$ | $4\times N=4\times 24\times 10^6$ | $N+ \sqrt N=8024000$ |
然后发现都不可行
怎么办呢?
其实
线段树
没必要开全
我们可以开到长度为16就不开了
时间乘10^616
内存可以做到\(1.75\times N\)
#include <iostream>
#include <string>
//#include <fstream>
using namespace std;
//ifstream inf("stp.in", ios_base::in);
//ofstream outf("stp.out", ios_base::out);
const int MAXN=1111111;
const int Len=15;
string com;
int L, R;
long long op;
int N, M;
long long Num[MAXN];
struct Node{
int r, l, ls, rs;
long long sum, opt;
} T[MAXN>>3];
int Tcnt=0;
long long getsum(int l, int r){
long long ret=0LL;
for(int i=l;i<=r;++i) ret+=Num[i];
return ret;
}
void getup(int l, int r){
for(int i=l;i<=r;++i) Num[i]+=op;
}
void pup(int at){
if(T[at].r-T[at].l<=Len) T[at].sum=getsum(T[at].l, T[at].r);
else T[at].sum=T[T[at].ls].sum+T[T[at].rs].sum;
}
void BuildTree(int l, int r, int at){
T[at].l=l;T[at].r=r;T[at].opt=0LL;
T[at].ls=-1;T[at].rs=-1;
if(r-l>Len){
int m=(l+r)>>1;
++Tcnt;T[at].ls=Tcnt;
BuildTree(l, m, Tcnt);
++Tcnt;T[at].rs=Tcnt;
BuildTree(m+1, r, Tcnt);
}
pup(at);
}
void cop(int at){
T[at].opt+=op;
}
void opr(int at){
T[at].sum+=(long long)(T[at].r-T[at].l+1)*op;
}
void pdw(int at){
if(T[at].opt==0LL) return;
int top=op;op=T[at].opt;
if(T[at].r-T[at].l<=Len){
getup(T[at].l, T[at].r);
}
else{
opr(T[at].ls);cop(T[at].ls);
opr(T[at].rs);cop(T[at].rs);
}
op=top;T[at].opt=0LL;
}
long long Ask(int at){
if(T[at].l>=L && T[at].r<=R){
return T[at].sum;
}
long long ret=0LL;
pdw(at);
if(T[at].r-T[at].l<=Len){
ret=getsum(max(T[at].l, L), min(T[at].r, R));
// for(int i=max(T[at].l, L);i<=min(T[at].r, R);++i)
// ret+=Num[i];
}
else{
int m=(T[at].l+T[at].r)>>1;
if(L<=m) ret+=Ask(T[at].ls);
if(R>m) ret+=Ask(T[at].rs);
}
return ret;
}
void Update(int at){
if(T[at].l>=L && T[at].r<=R){
opr(at);cop(at);
return;
}
pdw(at);
if(T[at].r-T[at].l<=Len){
getup(max(T[at].l, L), min(T[at].r, R));
// for(int i=max(T[at].l, L);i<=min(T[at].r, R);++i)
// Num[i]+=op;
}
else{
int m=(T[at].l+T[at].r)>>1;
if(L<=m) Update(T[at].ls);
if(R>m) Update(T[at].rs);
}
pup(at);
}
int main(){
ios_base::sync_with_stdio(false);
cin >> N >> M;
for(int i=1;i<=N;++i) cin >> Num[i];
++Tcnt;
BuildTree(1, N, Tcnt);
for(int i=1;i<=M;++i){
cin >> com;
if(com[1]=='s'){
cin >> L >> R;
cout << Ask(1) << endl;
}
else{
cin >> L >> R >> op;
Update(1);
}
}
return 0;
}