【HDU5930 2016CCPC東北地區大學生程式設計競賽
阿新 • • 發佈:2018-12-23
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x,y) memset(x,y,sizeof(x)) #define rt 1, 1, n #define ls o<<1 #define rs o<<1|1 #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; } const int N = 5e4 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, m; int a[1 << 17]; //a[i]維護線段樹第i個節點的區間gcd值 int b[N]; //b[i]維護第i個位置的數值 int gcd(int x, int y) { return y == 0 ? x : gcd(y, x%y); } void pushup(int o) { a[o] = gcd(a[ls], a[rs]); } void build(int o, int l, int r) { if (l == r) { a[o] = b[l]; return; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(o); } int P, V; void modify(int o, int l, int r) { if (l == r) { a[o] = V; return; } int mid = (l + r) >> 1; P <= mid ? modify(lson) : modify(rson); pushup(o); } int L, R, G, TP; int query(int o, int l, int r) { if (l >= L && r <= R && a[o] % G == 0)return 0; if (l == r)return l; int mid = (l + r) >> 1; int tmp = 0; if (TP == 0) { if (R > mid)tmp = query(rson); if (tmp)return tmp; if (L <= mid)return query(lson); } else { if (L <= mid)tmp = query(lson); if (tmp)return tmp; if (R > mid)return query(rson); } return tmp; } vector< pair<int, int> >lft, rgt; LL cnt[1000010];int ans; int dfn[1000010]; int tim; void cal(int P, int sig, bool init = 0) { lft.clear(); rgt.clear(); int i, p; //get lft TP = 0; p = P; for (i = p, G = b[p]; i >= 1; i = p, G = gcd(G, b[p])) { L = 1; R = i; p = query(rt); lft.push_back({ i - p, G }); } //get rgt if (!init) { TP = 1; p = P; for (i = p, G = b[p]; i <= n; i = p, G = gcd(G, b[p])) { L = i; R = n; p = query(rt); if (p == 0) p = n + 1; rgt.push_back({ p - i, G }); } } else rgt.push_back({ 1, b[p] }); for (auto l : lft) { for (auto r : rgt) { LL num = (LL)l.first * r.first; int g = gcd(l.second, r.second); if (dfn[g] != tim)dfn[g] = tim, cnt[g] = 0; if (cnt[g] == 0)++ans; cnt[g] += num * sig; if (cnt[g] == 0)--ans; } } } void init() { for (int i = 1; i <= n; ++i)cal(i, 1, 1); } int main() { scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i)scanf("%d", &b[i]); build(rt); ++tim; ans = 0; init(); printf("Case #%d:\n", casei); for (int i = 1; i <= m; ++i) { scanf("%d%d", &P, &V); cal(P, -1); b[P] = V; modify(rt); cal(P, 1); printf("%d\n", ans); } } return 0; } /* 【題意】 有n(50000)個數a[](1e6範圍)和q(50000)個操作 對於每個操作,我們會修改a[p]為v 問你每次修改之後會剩下多少個不同的區間連續gcd 【型別】 資料結構 【分析】 一個點的gcd值會影響所有包含其的區間 我們先預處理出n(n+1)個區間的gcd值,用一個cnt陣列完成計數 然後對於修改,我們查詢出包含這個點的所有區間段(這個可以通過線上段樹上二分實現),在cnt陣列中消除即可 然後再修改,再在cnt陣列中加回去完成計數即可 複雜度的瓶頸在於我們合併區間時的左log個gcd區間和右log的gcd區間再求gcd導致的(log)^3 【時間複雜度&&優化】 O(nlognlognlogn) 【資料】 input 2 3 2 1 2 3 1 3 2 3 ans 3 1 input 3 2 3 3 3 1 1 2 2 ans 2 3 */