BZOJ3211 花神游历各国 线段树
题意:给定一个数列,维护:1、区间求和 2、区间开根号
题解:
线段树,唯一的优化就是如果某区间的和为0和1,就不再向下进行更新。(注意long long)
另外动态开内存真的好慢- -,我的机子上3s(注意是s)才跑完一次,评测机T的不要不要的。
#include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef struct NODE{ NODE *lchild,*rchild; int L,R; long long sum; bool lazy; NODE(){} }*TREE; TREE root; int n,m; void Pushup(TREE & node){ node->sum=node->lchild->sum+node->rchild->sum; node->lazy=node->lchild->lazy&node->rchild->lazy; } void Build(TREE & root,int l,int r){ root=new NODE; root->L=l,root->R=r,root->sum=root->lazy=0; if(l==r){ scanf("%lld",&root->sum); if(root->sum==0 || root->sum==1) root->lazy=1; return; } int m=(l+r)>>1; Build(root->lchild,l,m); Build(root->rchild,m+1,r); Pushup(root); } long long Query(TREE & root,int l,int r){ if(l<=root->L && r>=root->R) return root->sum; int m=(root->L+root->R)>>1; long long tmp=0; if(l<=m) tmp+=Query(root->lchild,l,r); if(r>=m+1) tmp+=Query(root->rchild,l,r); return tmp; } void Update(TREE & root,int l,int r){ if(root->lazy) return; if(root->L==root->R){ root->sum=(long long)sqrt(root->sum); if(root->sum==1 || root->sum==0) root->lazy=1; return; } int m=(root->L+root->R)>>1; if(l<=m) Update(root->lchild,l,r); if(r>m) Update(root->rchild,l,r); Pushup(root); } void Delete(TREE & root){ if(root->L==root->R){ delete root; return; } Delete(root->lchild); Delete(root->rchild); delete root; } void Visit(TREE & root){ if(root->L==root->R){ cout << root->sum << " "; return; } Visit(root->lchild); Visit(root->rchild); cout << root->sum << " "; } int main(){ cin >> n; Build(root,1,n); cin >> m; int x,l,r; while(m--){ cin >> x >> l >> r; l=min(l,r),r=max(l,r); if(x==1) cout << Query(root,l,r) << endl; if(x==2) Update(root,l,r); } Delete(root); return 0; }