[BZOJ3211]花神游历各国

线段树题,打个标记即可,因为如果那个位置的值被降到了1/0,再怎么sqrt它也不会变。如果一个节点的两个子树已经全部被打了标记,那么就不用再更新了。
这份代码因为一开始打错了疯狂T,加了各种鬼畜优化。。。(貌似这的跑的能快一点点)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstring>
const int N=100005;
typedef long long ll;
struct Segtree {
	ll l,r,sum;
	bool flag;
} t[N<<2];
ll a[N],n,m;
ll rd() {
	ll x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x;
}
void pushup(int cur) {
	cur[t].sum=(cur<<1)[t].sum+(cur<<1|1)[t].sum;
	cur[t].flag=(cur<<1)[t].flag&(cur<<1|1)[t].flag;
}
void build(int cur,int l,int r) {
	cur[t].l=l;
	cur[t].r=r;
	if(l==r) {
		cur[t].sum=rd();
		if(cur[t].sum==1||cur[t].sum==0) cur[t].flag=1;
		return;
	}
	int mid=l+r>>1;
	build(cur<<1,l,mid);
	build(cur<<1|1,mid+1,r);
	pushup(cur);
}
void update(int l,int r,int cur) {
	if(cur[t].flag) return;
	if(cur[t].l==cur[t].r) {
		cur[t].sum=(ll)sqrt(cur[t].sum);
		if(t[cur].sum==1||cur[t].sum==0) cur[t].flag=1;
		return;
	}
	int mid=cur[t].l+cur[t].r>>1;
	if(l>mid) update(l,r,cur<<1|1);
	else if(r<=mid) update(l,r,cur<<1);
	else update(l,mid,cur<<1),update(mid+1,r,cur<<1|1);
	pushup(cur);
}
ll query(int l,int r,int cur) {
	if(cur[t].l>=l&&r>=cur[t].r)return cur[t].sum;
	int mid=cur[t].l+cur[t].r>>1;
	if(mid>=r) return query(l,r,cur<<1);
	else if(l>mid) return query(l,r,cur<<1|1);
	else return query(l,mid,cur<<1)+query(mid+1,r,cur<<1|1);
}
int main() {
	scanf("%d",&n);
	build(1,1,n);
	scanf("%d",&m);
	int opt,l,r;
	while(m--) {
		opt=rd();l=rd();r=rd();
		if(l>r) std::swap(l,r);
		if(opt==1)
			printf("%lld\n",query(l,r,1));
		else update(l,r,1);
	}
}
posted @ 2018-07-12 19:40  SWHsz  阅读(102)  评论(0编辑  收藏  举报