HDU - 5381 The sum of gcd(離線處理 + 線段樹)
阿新 • • 發佈:2018-12-19
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5381
題目大意:給出一個長度為 n 的陣列a,現在有q次詢問,每次詢問給出一個區間 [L,R],要你求出這個區間內所有子區間的gcd之和,即求。
題目思路:根據gcd的性質,以L為起點,終點小於等於R的子區間所得到的不同的gcd個數不超過個。所以對於一開始給出的每一個值a[i],我們就可以維護出以這個點為起點,終點從 i 到 n 的子區間的gcd值。
既然這樣,我們就可以維護一棵線段樹,線段樹中下標為 i 的結點表示以 i 為終點的所有子區間的gcd之和。同時倒著將a陣列內的值更新到線段樹中。在更新的同時我們還要將相同的gcd值進行合併,記錄每一段的資訊即可。
在查詢答案時,我們可以用一個vector來儲存查詢區間的左端點為L的所有區間,當更新到這個端點時,我們就對其所在的區間進行查詢,由於我們是倒著更新a陣列內的值,所以這個區間的右端點的值一定是已經被更新了的。
時間複雜度是
具體實現看程式碼:
#include <bits/stdc++.h> #define fi first #define se second #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pb push_back #define MP make_pair #define lowbit(x) x&-x #define clr(a) memset(a,0,sizeof(a)) #define _INF(a) memset(a,0x3f,sizeof(a)) #define FIN freopen("in.txt","r",stdin) #define IOS ios::sync_with_stdio(false) #define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int>pii; typedef pair<ll, ll>pll; const int MX = 1e4 + 5; int n, q, _; vector<pii>p[MX]; int a[MX]; ll sum[MX << 2], lazy[MX << 2], ans[MX]; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } void push_up(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void push_down(int l, int r, int rt) { if (lazy[rt]) { int m = (l + r) >> 1; lazy[rt << 1] += lazy[rt]; lazy[rt << 1 | 1] += lazy[rt]; sum[rt << 1] += lazy[rt] * (m - l + 1); sum[rt << 1 | 1] += lazy[rt] * (r - m); lazy[rt] = 0; } } void build(int l, int r, int rt) { sum[rt] = lazy[rt] = 0; if (l == r) return; int m = (l + r) >> 1; build(lson); build(rson); push_up(rt); } void update(int L, int R, int d, int l, int r, int rt) { if (L <= l && r <= R) { sum[rt] += (ll)(r - l + 1) * d; lazy[rt] += d; return; } push_down(l, r, rt); int m = (l + r) >> 1; if (L <= m) update(L, R, d, lson); if (R > m) update(L, R, d, rson); push_up(rt); } ll query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return sum[rt]; push_down(l, r, rt); ll res = 0; int m = (l + r) >> 1; if (L <= m) res += query(L, R, lson); if (R > m) res += query(L, R, rson); return res; } int g[MX], l[MX], r[MX]; int Merage(int cnt) { int j = 0; for (int i = 0; i < cnt; j++, i++) { g[j] = g[i]; l[j] = l[i]; r[j] = r[i]; while (g[i] == g[i + 1]) { l[j] = min(l[j], l[i + 1]); r[j] = max(r[j], r[i + 1]); i++; } } return j; } int main() { // FIN; for (scanf("%d", &_); _; _--) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), p[i].clear(); build(1, n, 1); scanf("%d", &q); for (int i = 1; i <= q; i++) { int L, R; scanf("%d%d", &L, &R); p[L].pb(MP(R, i)); } int cnt = 0; for (int i = n; i >= 1; i--) { for (int j = 0; j < cnt; j++) { int x = gcd(g[j], a[i]); g[j] = x; } g[cnt] = a[i]; l[cnt] = r[cnt] = i; cnt++; cnt = Merage(cnt); for (int j = 0; j < cnt; j++) update(l[j], r[j], g[j], 1, n, 1); for (auto now : p[i]) ans[now.se] = query(i, now.fi, 1, n, 1); } for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]); } return 0; }