1. 程式人生 > >bzoj3211 花神遊歷各國

bzoj3211 花神遊歷各國

() zoj 同時 多次 pac sig blank can tdi

傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=3211

【題解】

區間開根號,由於每個數被開根號不會很多次就變成1,每次我們暴力開根下去,同時記錄s[x]表示x這個區間內是不是全是1,如果是就不用開下去了

這樣保證了每個數最多被開不多次。

技術分享
# include <math.h>
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace
std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n; int seq[M]; ll w[M]; bool s[M]; inline void build(int x, int l, int r) { s[x] = 0; if(l == r) { w[x]
= seq[l]; return ; } int mid = l+r>>1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); w[x] = w[x<<1] + w[x<<1|1]; } inline void change(int x, int l, int r, int L, int R) { if(s[x]) return; if(l == r) { w[x] = sqrt(w[x]);
if(w[x] <= 1) s[x] = 1; return ; } int mid = l+r>>1; if(R <= mid) change(x<<1, l, mid, L, R); else if(L > mid) change(x<<1|1, mid+1, r, L, R); else change(x<<1, l, mid, L, mid), change(x<<1|1, mid+1, r, mid+1, R); w[x] = w[x<<1] + w[x<<1|1]; s[x] = s[x<<1] & s[x<<1|1]; } inline ll query(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return w[x]; int mid = l+r>>1; if(R <= mid) return query(x<<1, l, mid, L, R); else if(L > mid) return query(x<<1|1, mid+1, r, L, R); else return query(x<<1, l, mid, L, mid) + query(x<<1|1, mid+1, r, mid+1, R); } int main() { scanf("%d", &n); for (int i=1; i<=n; ++i) scanf("%d", seq+i); build(1, 1, n); int q; scanf("%d", &q); while(q--) { int opt, l, r; scanf("%d%d%d", &opt, &l, &r); if(l>r) swap(l, r); if(opt == 1) { printf("%lld\n", query(1, 1, n, l, r)); } else change(1, 1, n, l, r); } return 0; }
View Code

bzoj3211 花神遊歷各國