这道题看一眼就知道是线段树的题目,但是一看,题目要求区间开方,我就又傻了。想了一会,发现就算是109在开方5次之后就变成1了,所以就算是我们单个开方,时间复杂度也就是O(NlogN)。但是为了避免重复开方,我们要给线段树的每一个节点做一个标记,表示下面的区间是否全部为1和0。那样我们就可以避免重复开方了。
代码:
#include#include #define LL long longinline void swap(int &a, int &b) { int c = a; a = b; b = c;}#define MAXN 100005inline void GET(LL &n){ n = 0; char c; do c = getchar(); while(c > '9' || c < '0'); while(c <= '9' && c >= '0') {n = n * 10 + c - '0'; c = getchar();}}inline void GET(int &n){ n = 0; char c; do c = getchar(); while(c > '9' || c < '0'); while(c <= '9' && c >= '0') {n = n * 10 + c - '0'; c = getchar();}}struct node{ LL sum; bool lazy; node(){lazy = 0;}}t[MAXN<<1];inline int idx(int l, int r) { return (l + r) | (l != r);}void pushup(int l, int r){ int mid = (l + r) >> 1; t[idx(l, r)].sum = t[idx(l, mid)].sum + t[idx(mid+1, r)].sum; t[idx(l, r)].lazy = t[idx(l, mid)].lazy && t[idx(mid+1, r)].lazy;}void build(int l, int r){ int i = idx(l, r); if(l == r) { GET(t[i].sum); return; } int mid = (l + r) >> 1; build(l, mid); build(mid+1, r); t[idx(l, r)].sum = t[idx(l, mid)].sum + t[idx(mid+1, r)].sum;}int op, L, R, n, m;void Ins(int l, int r){ int i = idx(l, r); if(l > R || r < L) return; if(t[i].lazy) return; if(l == r) { t[i].sum = sqrt(t[i].sum); if(t[i].sum == 1 || t[i].sum == 0) t[i].lazy = 1; return; } int mid = (l + r) >> 1; Ins(l, mid); Ins(mid+1, r); pushup(l, r);}LL Sum(int l, int r){ if(l > R || r < L) return 0; if(l >= L && r <= R) return t[idx(l, r)].sum; int mid = (l+r)>>1; return Sum(l, mid) + Sum(mid+1, r);}int main(){ GET(n); build(1, n); GET(m); while(m --) { GET(op);GET(L);GET(R); if(op == 2) Ins(1, n); else if(op == 1) printf("%lld\n", Sum(1, n)); } return 0;}