Description

Input

Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
一些想法
一句话题意:区间开方,区间求和。
简述:对于任意一个10^9内的数,开平方最多不超过10次就会变成1或0,对于区间开方,我们跳过1或0,就变成了单点修改,区间求和,使用线段树或者树状数组。那么如何跳过1或者0呢?我们使用并查集维护,对于1或0它们的父亲是右边第一个不为0或1的数,在对于0或1,我们不开方直接跳过。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define debug(x) cerr<<#x<<'='<<x<<endl #define M 200004 #define N 100005 #define LL long long LL A[N],C[N]; LL father[N]; LL t,l,r,n,m; LL lowbit(LL x){ return x&(-x); } LL Query(LL x){ LL ret=0; while (x>0){ ret+=C[x]; x-=lowbit(x); } return ret; } void Add(LL x,LL y){ while (x<=n){ C[x]+=y; x+=lowbit(x); } } LL Find(LL x){ LL k,j,r; r=x; while (r!=father[r]) r=father[r]; k=x; while (k!=r) { j=father[k]; father[k]=r; k=j; } return r; } int main (){ cin>>n; for (int i=1;i<=n+1;i++) father[i]=i; for (int i=1;i<=n;i++) { scanf("%lld",&A[i]); Add(i,A[i]); } cin>>m; for (int i=1;i<=m;i++){ scanf("%lld%lld%lld",&t,&l,&r); if (t==1){ printf("%lld\n",Query(r)-Query(l-1)); } if (t==2){ for (int i=Find(l);i<=r;i=Find(i+1)){ int lee=floor(sqrt(A[i])); Add(i,lee-A[i]); A[i]=lee; if (lee==1||lee==0) father[i]=Find(i+1); } } } return 0; }
浮一大白
春天的酒如果没来得及喝掉就该洒在泥土里
不能灌醉你
灌醉一朵小花儿也好哇
Sylvia
二零一七年八月七日