算是裸线段树了,因为没个数最多开63次 ,开到不能再看就标记。查询时,如果某段区间被标记直接返回结果,否则继续向儿子节点更新。
注意用——int64
注意L会大于R 这点我很纠结。。您出题人故意的吗 WAn次。。
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 using namespace std; 11 #define N 100010 12 #define LL __int64 13 #define INF 0xfffffff 14 const double eps = 1e-8; 15 const double pi = acos(-1.0); 16 const double inf = ~0u>>2; 17 LL s[N<<2],f[N<<2]; 18 LL a[N]; 19 void up(int w) 20 { 21 s[w] =s[w<<1]+s[w<<1|1]; 22 f[w] = (f[w<<1]&&f[w<<1|1]); 23 } 24 void build(int l,int r,int w) 25 { 26 if(l==r) 27 { 28 s[w] = a[l]; 29 if(a[l]==1||a[l]==0) f[w] = 1; 30 return ; 31 } 32 int m = (l+r)>>1; 33 build(l,m,w<<1); 34 build(m+1,r,w<<1|1); 35 up(w); 36 } 37 void update(int a,int b,int l,int r,int w) 38 { 39 if(a<=l&&b>=r) 40 { 41 if(l==r) 42 { 43 LL k = sqrt(s[w]*1.0); 44 if(k*k>s[w]) 45 k--; 46 s[w] = k; 47 if(s[w]<=1) 48 f[w] = 1; 49 // up(w); 50 return ; 51 } 52 if(f[w]) 53 { 54 up(w); 55 return ; 56 } 57 else 58 { 59 int m = (l+r)>>1; 60 if(a<=m) 61 update(a,b,l,m,w<<1); 62 if(b>m) 63 update(a,b,m+1,r,w<<1|1); 64 up(w); 65 return ; 66 } 67 } 68 int m = (l+r)>>1; 69 if(a<=m) 70 update(a,b,l,m,w<<1); 71 if(b>m) 72 update(a,b,m+1,r,w<<1|1); 73 up(w); 74 } 75 LL query(int a,int b,int l,int r,int w) 76 { 77 if(a<=l&&b>=r) 78 { 79 return s[w]; 80 } 81 int m = (l+r)>>1; 82 LL res = 0; 83 if(a<=m) res+=query(a,b,l,m,w<<1); 84 if(b>m) res+=query(a,b,m+1,r,w<<1|1); 85 return res; 86 } 87 int main() 88 { 89 int i,n,q; 90 int k,x,y,kk=0; 91 while(scanf("%d",&n)!=EOF) 92 { 93 memset(f,0,sizeof(f)); 94 for(i = 1; i <=n ;i++) 95 { 96 scanf("%I64d",&a[i]); 97 } 98 build(1,n,1); 99 scanf("%d",&q); 100 printf("Case #%d:\n",++kk); 101 while(q--) 102 { 103 scanf("%d%d%d",&k,&x,&y); 104 if(x>y) swap(x,y); 105 if(k) 106 { 107 printf("%I64d\n",query(x,y,1,n,1)); 108 } 109 else 110 { 111 update(x,y,1,n,1); 112 } 113 } 114 puts(""); 115 } 116 return 0; 117 }