Can you answer these queries? HDU
阿新 • • 發佈:2018-12-20
題意
給定n個數,分別代表每一個戰艦的耐力值。有m個操作,當 t=1時,輸出x~y的戰艦耐力值之和,當 t=0時,使x~y戰艦的每一個耐力值都變為原來的平方根(向下取整)。
思路
遍歷 x到y 的每一個葉子節點,使他們的值變為原來的平方根,結果超時了。因為 1 的平方根還是 1,所以在更新時判斷這段區間的值是否都為1,如果都為1就不需要更新。
一開始以為會用到標記陣列,最後發現根本不許需要那麼麻煩。。。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=262144; ll sum[maxn],node[maxn/2]; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void bulid(int l,int r,int rt) { if(l==r) { sum[rt]=node[l]; return ; } int m=(l+r)>>1; bulid(l,m,rt<<1); bulid(m+1,r,rt<<1|1); pushup(rt); } void update(int L,int R,int l,int r,int rt) //更新 L~R區間 { if(l==r) { sum[rt]=sqrt(sum[rt]); return ; } if(L<=l && R>=r && sum[rt]==r-l+1) //優化 判斷區間的值是否都為1 return ; int m=(l+r)>>1; if(L<=m) update(L,R,l,m,rt<<1); if(R>m) update(L,R,m+1,r,rt<<1|1); pushup(rt); } ll query(int L,int R,int l,int r,int rt) // L~R區間求和 { if(L<=l && R>=r) return sum[rt]; ll cnt=0; int m=(l+r)>>1; if(L<=m) cnt+=query(L,R,l,m,rt<<1); if(R>m) cnt+=query(L,R,m+1,r,rt<<1|1); return cnt; } int main() { int n,m,k=1; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%lld",&node[i]); bulid(1,n,1); scanf("%d",&m); int x,y,z; printf("Case #%d:\n",k++); while(m--) { scanf("%d%d%d",&z,&x,&y); if(x>y) //當 x>y時,交換兩點的值 swap(x,y); if(z==1) printf("%lld\n",query(x,y,1,n,1)); else update(x,y,1,n,1); } printf("\n"); } return 0; }