题意:
给一个序列,有俩种操作,一种是求区间和,一种是将区间每个数开根号后向下取整(QQ浏览器翻译成了四舍五入,坑了我很久)。
思路:
因为是对区间内的每个数开根号,没有办法用延迟更新,但是取根号在6,7次就会到1,所以如果父节点的权值等于r-l+1就不用往下跟新了,因为这个区间里每个数都是1,这样修改的复杂度就很低了总复杂度是
题目说的是对x到y进行操作,并没有说明x、y的大小关系,所以x可能会大于y,需要交换x、y
Code:
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std; typedef long long ll; const int maxn=1e5+7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } ll tree[maxn<<2]; inline void build(int l,int r,int rt) { if(l==r) { tree[rt]=read(); return; } int mid=l+r>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } inline void update(int x,int y,int l,int r,int rt) { if(tree[rt]==r-l+1) return; if(l==r) { tree[rt]=sqrt(tree[rt]); return; } int mid=l+r>>1; if(x<=mid) update(x,y,l,mid,rt<<1); if(y>mid) update(x,y,mid+1,r,rt<<1|1); tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } inline ll query(int x,int y,int l,int r,int rt) { if(x<=l&&r<=y) return tree[rt]; int mid=l+r>>1; ll ans=0; if(x<=mid) ans=query(x,y,l,mid,rt<<1); if(y>mid) ans+=query(x,y,mid+1,r,rt<<1|1); return ans; } int main() { int n,m,t,x,y,cas=0; while(~scanf("%d",&n)) { build(1,n,1); m=read(); printf("Case #%d:\n",++cas); while(m--) { t=read(),x=read(),y=read(); if(x>y) swap(x,y); if(t) printf("%lld\n",query(x,y,1,n,1)); else update(x,y,1,n,1); } puts(""); } return 0; }