hdu 4027 Can you answer these queries?(線段樹)(單點更新 但需要標記記錄剪枝)
阿新 • • 發佈:2019-02-12
題目:http://acm.hdu.edu.cn/showproblem.php?pid=4027
題目大意:給定100000個數,兩種操作,0 i j表示將i j這段的數字都開根號(向下取整),1 i j表示查詢i j之間的所有值的和。。。(所有的和都不超過64位)..(用long long)
思路:因為是開根號,所以是要查詢到葉節點對葉節點進行開根號處理
這裡需要用到開個陣列記錄,如果葉節點小於等於1時再開根號值就不會發生變化,則將此位置標記為1,則下次要到這個位置時再不要在往下更新
#include<iostream> #include<cmath> #include<cstdio> #include<iomanip> #include<cstring> #include<stdlib.h> #include<string> #include<algorithm> #include<queue> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn =110000; long long sum[maxn<<2]; long long col[maxn<<2]; void pushup(int rt)//將當前結點的資訊更新的父節點 { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; col[rt]=col[rt<<1]&&col[rt<<1|1]; } void build(int l,int r,int rt)//建立線段樹 { if(l==r) { scanf("%lld",&sum[rt]); return ; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } long long query(int L,int R,int l,int r,int rt) { if(l>=L&&r<=R) return sum[rt]; int m=(l+r)>>1; long long ret=0; if(L<=m)ret+=query(L,R,lson); if(R>m)ret+=query(L,R,rson); pushup(rt); return ret; } void update(int L,int R,int l,int r,int rt) { if(l==r) { sum[rt]=(int)sqrt((double)sum[rt]); if(sum[rt]<=1) col[rt]=1;//如果小於等於1時 開根號值不變 不需要在進行開根號操作 return ; } int m=(l+r)>>1; if (L<=m&&!col[rt<<1])update(L,R,lson);//判斷是否需要往下更新 if (R>m&&!col[rt<<1|1])update(L,R,rson); pushup(rt);//子節點更新完之後也要對其父節點不斷往上的更新 } int main() { int n,m; int t=1; while(~scanf("%d",&n)) { memset(col,0,sizeof col); memset(sum,0,sizeof sum); build(1,n,1); scanf("%d",&m); int a; long long b,c; printf("Case #%d:\n",t++); for(int i=0;i<m;i++) { scanf("%d%lld%lld",&a,&b,&c); if(b>c)swap(b,c); if(a==0) { update(b,c,1,n,1); } else { printf("%lld\n",query(b,c,1,n,1)); } } printf("\n"); } }