洛谷 P5610 [Ynoi2013] 大學
阿新 • • 發佈:2021-01-11
一個長為 \(n\) 的非負整數序列 \(a\),支援以下兩個操作:
1 l r x
:把區間 \([l,r]\) 中所有 \(x\) 的倍數除以 \(x\)。2 l r
:查詢區間 \([l,r]\) 的和。
本題強制線上,每次的 \(l,r,x\) 需要 xor 上上次答案,如果之前沒有詢問,則上次答案為 \(0\)。
\(1\leq n,m\leq 10^5\),\(0\leq a_i\leq 5\times 10^5\),解密後的 \(x,l,r\) 滿足 \(1\leq x\leq 5\times 10^5\),\(1\leq l\leq r\leq n\)。
卡常太難了/kk
發現一個數被操作的次數不會很多,最多操作 \(loga_i\)
但是這樣子中間的被除過之後不是 \(x\) 的倍數會被訪問很多次,那麼考慮開個並查集,如果一個數被操作之後不是 \(x\) 的倍數,就把他合併在下一個數的下面。
因為對每個數的因數都要合併一次,然後要進行 \(nloga_i\)次修改,所以複雜度是 \(O(nd(a_i)\alpha(n)+mlognloga_i)\) 。
不過這題太卡常了,所以可以不用vector換用手寫記憶體池。
但是我還是卡不過去,就給有 \(200\) 個因子的數的因子打了個表/kk
Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #define reg register const int N = 1e5; const int M = 5e5; const int MAXN = 2e7; using namespace std; int n,m,a[N + 5],pool[MAXN + 5],pool2[MAXN + 5],t[M + 5]; int *p = pool,*p1 = pool2; int *d[M + 5],di[500] = {0,2,3,4,5,6,7,8,9,10,11,12,14,15,16,18,20,21,22,24,27,28,30,33,35,36,40,42,44,45,48,54,55,56,60,63,66,70,72,77,80,81,84,88,90,99,105,108,110,112,120,126,132,135,140,144,154,162,165,168,176,180,189,198,210,216,220,231,240,252,264,270,280,297,308,315,324,330,336,360,378,385,396,405,420,432,440,462,495,504,528,540,560,567,594,616,630,648,660,693,720,756,770,792,810,840,880,891,924,945,990,1008,1080,1134,1155,1188,1232,1260,1296,1320,1386,1485,1512,1540,1584,1620,1680,1782,1848,1890,1980,2079,2160,2268,2310,2376,2520,2640,2772,2835,2970,3024,3080,3240,3465,3564,3696,3780,3960,4158,4455,4536,4620,4752,5040,5544,5670,5940,6160,6237,6480,6930,7128,7560,7920,8316,8910,9072,9240,10395,11088,11340,11880,12474,13860,14256,15120,16632,17820,18480,20790,22680,23760,24948,27720,31185,33264,35640,41580,45360,49896,55440,62370,71280,83160,99792,124740,166320,249480,498960}; struct Bit { long long c[N + 5]; inline int lowbit(int x) { return x & (-x); } inline void add(int x,int v) { for (;x <= n;x += lowbit(x)) c[x] += v; } inline long long query(int x) { long long ans = 0; for (;x;x -= lowbit(x)) ans += c[x]; return ans; } }c; struct Dsu { int *fa,ts; inline void init(int n) { fa = p; p += n; for (int i = 0;i < n;i++) fa[i] = i; ts = n; } inline int find(int x) { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } }fd[M + 5]; void prework() { for (reg int i = 1;i <= M;i++) for (reg int j = i + i;j <= M;j += i) t[i] += t[j]; for (reg int i = 1;i <= M;i++) if (t[i]) d[i] = p1,p1 += t[i],t[i] = 0; for (reg int i = 1;i <= n;i++) { c.add(i,a[i]); if (a[i] == 498960) { for (reg int j = 1;j <= 199;j++) d[di[j]][t[di[j]]++] = i; continue; } for (reg int j = 2;j * j <= a[i];j++) if (a[i] % j == 0) { d[j][t[j]++] = i; if (j * j != a[i]) d[a[i] / j][t[a[i] / j]++] = i; } if (a[i] != 0) d[a[i]][t[a[i]]++] = i; } for (reg int i = 1;i <= M;i++) if (t[i]) fd[i].init(t[i]); } inline long long read() { long long X(0);int w(0);char ch(0); while (!isdigit(ch)) w |= ch == '-',ch = getchar(); while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar(); return w ? -X : X; } int main() { //freopen("data.in","r",stdin); //freopen("a1.out","w",stdout); n = read();m = read(); for (reg int i = 1;i <= n;i++) a[i] = read(),t[a[i]]++; prework(); int opt; long long ans = 0,l,r,x; while (m--) { //ans = 0; opt = read();l = read() ^ ans;r = read() ^ ans; if (opt == 1) { x = read() ^ ans; if (x == 1) continue; if (!fd[x].ts) continue; int st = lower_bound(d[x],d[x] + t[x],l) - d[x]; for (reg int i = st;i < fd[x].ts;i++) { i = fd[x].find(i); if (d[x][i] > r || i >= fd[x].ts) break; if (a[d[x][i]] % x != 0) { if (i + 1 < fd[x].ts) fd[x].fa[i] = fd[x].find(fd[x].fa[i + 1]); else fd[x].ts--; } else { c.add(d[x][i],a[d[x][i]] / x - a[d[x][i]]); a[d[x][i]] /= x; if (a[d[x][i]] % x != 0) { if (i + 1 < fd[x].ts) fd[x].fa[i] = fd[x].find(fd[x].fa[i + 1]); } } } } else { ans = c.query(r) - c.query(l - 1); printf("%lld\n",ans); } } return 0; }