BZOJ_3038_上帝造題的七分鐘2_線段樹
阿新 • • 發佈:2018-02-25
表示範圍 pan clas oid 難度 fine class body bzoj
BZOJ_3038_上帝造題的七分鐘2_線段樹
題意:
XLk覺得《上帝造題的七分鐘》不太過癮,於是有了第二部。
"第一分鐘,X說,要有數列,於是便給定了一個正整數數列。
第二分鐘,L說,要能修改,於是便有了對一段數中每個數都開平方(下取整)的操作。
第三分鐘,k說,要能查詢,於是便有了求一段數的和的操作。
第四分鐘,彩虹喵說,要是noip難度,於是便有了數據範圍。
第五分鐘,詩人說,要有韻律,於是便有了時間限制和內存限制。
第六分鐘,和雪說,要省點事,於是便有了保證運算過程中及最終結果均不超過64位有符號整數類型的表示範圍的限制。
第七分鐘,這道題終於造完了,然而,造題的神牛們再也不想寫這道題的程序了。"
——《上帝造題的七分鐘·第二部》
所以這個神聖的任務就交給你了。
分析:
在2^64-1以內每個數最多被開方6次就會變成1,或者這個數一開始就是零。
用線段樹維護區間和,再記錄下區間裏的數有沒有變成1。
代碼:
#include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> using namespace std; #define N 262145 #define LL long long #define BUG puts("Fuck") int ls[N],rs[N],n,m,cnt; LL t[N],len[N]; void bt(int l,int r,int &p){ if(!p)p=++cnt; if(l==r){ scanf("%lld",&t[p]); if(t[p])len[p]=1;return ; } int mid=l+r>>1; bt(l,mid,ls[p]);bt(mid+1,r,rs[p]); t[p]=t[ls[p]]+t[rs[p]]; len[p]=len[ls[p]]+len[rs[p]]; } void up(int l,int r,int x,int y,int p){ if(t[p]==len[p])return ; if(l==r){t[p]=(LL)sqrt(t[p]);return ;} int mid=l+r>>1; if(x<=mid)up(l,mid,x,y,ls[p]); if(y>mid)up(mid+1,r,x,y,rs[p]); t[p]=t[ls[p]]+t[rs[p]]; } LL query(int l,int r,int x,int y,int p){ if(x<=l&&r<=y)return t[p]; int mid=l+r>>1; LL re=0; if(x<=mid)re+=query(l,mid,x,y,ls[p]); if(y>mid)re+=query(mid+1,r,x,y,rs[p]); return re; } int main(){ scanf("%d",&n); int p=0; bt(1,n,p); scanf("%d",&m); int opt,x,y; while(m--){ scanf("%d%d%d",&opt,&x,&y); if(x>y)swap(x,y); if(opt==0){ p=1; up(1,n,x,y,p); }else{ p=1; printf("%lld\n",query(1,n,x,y,p)); } } } /* 10 1 2 3 4 5 6 7 8 9 10 5 0 1 10 1 1 10 1 1 5 0 5 8 1 4 8 */
BZOJ_3038_上帝造題的七分鐘2_線段樹