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;
}
posted @ 2018-03-20 23:15  Pickupwin  阅读(300)  评论(0编辑  收藏  举报