題目傳送門php
題目描述:html
花神喜歡步行遊歷各國,順便虐爆各地競賽。花神有一條遊覽路線,它是線型的,也就是說,全部遊歷國家呈一條線的形狀排列,花神對每一個國家都有一個喜歡程度(固然花神並不必定喜歡全部國家)。c++
每一次旅行中,花神會選擇一條旅遊路線,它在那一串國家中是連續的一段,此次旅行帶來的開心值是這些國家的喜歡度的總和,固然花神對這些國家的喜歡程序並非恆定的,有時會忽然對某些國家產生反感,使他對這些國家的喜歡度δ變爲√δ(多是花神虐爆了那些國家的 OI,從而感到乏味)。函數
如今給出花神每次的旅行路線,以及開心度的變化,請求出花神每次旅行的開心值。ui
輸入格式:spa
第一行是一個整數N,表示有N個國家;
第二行有N個空格隔開的整數,表示每一個國家的初始喜歡度;
第三行是一個整數M,表示有M條信息要處理;
第四行到最後,每行三個整數想x,l,r,當x=1時詢問遊歷國家x到r的開心值總和,也就是Σδi(l~r),當x=2時國家l到r中每一個國家的喜歡度δi變爲√δi。htm
輸出格式:blog
每次x=1時,每行一個整數。表示此次旅行的開心度。遞歸
樣例:get
樣例輸入:
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
樣例輸出:
101
11
11
數據範圍與提示:
對於所有數據,1≤n≤105,1≤m≤2×105,1≤l≤r≤n,0≤δi≤109。
注:建議使用sqrt函數,且向下取整。
一句話題意:線段樹區間開跟,區間求和。
題解:
區間信息沒法快速更新,沒法使用延遲標記。(可怕)
可是注意,109最多開5次跟就不變了
那麼,每次修改暴力遞歸下去,直到當前區間已全是0或1就return
是否是很帥?
代碼時刻:
#include<bits/stdc++.h> #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; int n,m; long long v[100001]; long long trsum[400001],trmax[400001]; void pushup(int x) { trsum[x]=trsum[L(x)]+trsum[R(x)]; trmax[x]=max(trmax[L(x)],trmax[R(x)]); } void build(int x,int l,int r) { if(l==r) { trsum[x]=trmax[x]=v[l]; return; } int mid=(l+r)>>1; build(L(x),l,mid); build(R(x),mid+1,r); pushup(x); } void change(int x,int l,int r,int L,int R) { if(l==r) { trsum[x]=sqrt(trsum[x]); trmax[x]=sqrt(trmax[x]); return; } if(trmax[x]<=1)return;//注意這裏爲≤,其餘跟普通線段樹別無兩樣 int mid=(l+r)>>1; if(L<=mid)change(L(x),l,mid,L,R); if(R>mid)change(R(x),mid+1,r,L,R); pushup(x); } long long ask(int x,int l,int r,int L,int R) { if(L<=l&&r<=R)return trsum[x]; int mid=(l+r)>>1; long long rec=0; if(L<=mid)rec+=ask(L(x),l,mid,L,R); if(R>mid)rec+=ask(R(x),mid+1,r,L,R); return rec; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&v[i]); build(1,1,n); scanf("%d",&m); while(m--) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if(op==1)printf("%lld\n",ask(1,1,n,l,r)); else change(1,1,n,l,r); } return 0; }
cpp
rp++