您的位置:首页 > 其它

[bzoj3211]花神游历各国

2016-06-11 18:45 260 查看

Description

写一个数据结构兹瓷区间求和和区间开方。

n<=10^5,m<=2*10^5,ai<=10^9

Solution

区间开平方?暴力开呗。

反正10^9也不需要开多少次,只不过常数大了点罢了。

用线段树维护区间和,还有区间标记,表示这个区间是不是还有可以开方的数(1&0)。

当然,用树状数组维护和再用并查集来打标记也是可以的,而且常数更小。

不过,有一个迷之问题,为什么一定要把0给标记,不然会惨绝人寰地超时?

表示奥妙重重。

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100005
using namespace std;
typedef long long ll;
struct note{ll v;bool bz;}t[N*3];
int n,m,z,x,y,a
;
void back(int v,int x) {
t[v].v=x;if (x==1||x==0) t[v].bz=1;
}
note merge(note y,note z) {
note x;x.v=y.v+z.v;x.bz=y.bz&&z.bz;return x;
}
void build(int v,int l,int r) {
if (l==r) {
back(v,a[l]);
return;
}
int m=(l+r)/2;
build(v*2,l,m);build(v*2+1,m+1,r);
t[v]=merge(t[v*2],t[v*2+1]);
}
void revise(int v,int l,int r) {
if (t[v].bz) return;
if (l==r) {
a[l]=sqrt(a[l]);
back(v,a[l]);
return;
}
int m=(l+r)/2;
revise(v*2,l,m);revise(v*2+1,m+1,r);
t[v]=merge(t[v*2],t[v*2+1]);
}
void change(int v,int l,int r,int x,int y) {
if (t[v].bz) return;
if (l==x&&r==y) {revise(v,l,r);return;}
int m=(l+r)/2;
if (y<=m) change(v*2,l,m,x,y);
else if (x>m) change(v*2+1,m+1,r,x,y);
else change(v*2,l,m,x,m),change(v*2+1,m+1,r,m+1,y);
t[v]=merge(t[v*2],t[v*2+1]);
}
ll find(int v,int l,int r,int x,int y) {
if (l==x&&r==y) return t[v].v;
int m=(l+r)/2;
if (y<=m) return find(v*2,l,m,x,y);
else if (x>m) return find(v*2+1,m+1,r,x,y);
else return find(v*2,l,m,x,m)+find(v*2+1,m+1,r,m+1,y);
}
int main() {
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
build(1,1,n);
for(scanf("%d",&m);m;m--) {
scanf("%d%d%d",&z,&x,&y);
if (z==1) printf("%lld\n",find(1,1,n,x,y));
else change(1,1,n,x,y);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: