1. 程式人生 > >【BZOJ】3038 上帝造題的七分鐘2

【BZOJ】3038 上帝造題的七分鐘2

bzoj 個數 opened 題解 namespace div .net 分鐘 一個數

【算法】線段樹||(坑...)

【題解】修改必須暴力單點修改,然後利用標記區間查詢。

優化:一個數經過不斷開方很快就會變成1,所以維護區間最大值。

修改時訪問到的子樹最大值<=1時,該區間就不必修改。

技術分享
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct treess{int k,l,r;long long maxs,sum;}t[maxn*3];
int n,m;long long
a[maxn]; void build(int k,int l,int r) { t[k].l=l;t[k].r=r; if(l==r)t[k].maxs=t[k].sum=a[l]; else { int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); t[k].maxs=max(t[k<<1].maxs,t[k<<1|1].maxs);//
printf("k=%d maxs=%d",k,t[k].maxs); t[k].sum=t[k<<1].sum+t[k<<1|1].sum; } } void update(int k,int l,int r) { int left=t[k].l,right=t[k].r; if(t[k].maxs<=1)return; if(left==right)a[left]=floor(sqrt(a[left])),t[k].maxs=t[k].sum=a[left]; else {
int mid=(left+right)>>1; if(l<=mid)update(k<<1,l,r); if(r>mid)update(k<<1|1,l,r); t[k].maxs=max(t[k<<1].maxs,t[k<<1|1].maxs); t[k].sum=t[k<<1].sum+t[k<<1|1].sum; } } long long ask(int k,int l,int r) { int left=t[k].l,right=t[k].r; if(l<=left&&right<=r)return t[k].sum; int mid=(left+right)>>1;long long ans=0; if(l<=mid)ans=ask(k<<1,l,r); if(r>mid)ans+=ask(k<<1|1,l,r); return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); scanf("%d",&m); build(1,1,n); for(int i=1;i<=m;i++) { int k,l,r; scanf("%d%d%d",&k,&l,&r); if(l>r)swap(l,r); if(k==0)update(1,l,r); else printf("%lld\n",ask(1,l,r)); } return 0; }
View Code

BZOJ 3211 花神遊歷各國 樹狀數組+並查集

【BZOJ】3038 上帝造題的七分鐘2