1. 程式人生 > 實用技巧 >洛谷 P5610 [Ynoi2013] 大學

洛谷 P5610 [Ynoi2013] 大學

一個長為 \(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\)

次,那麼可以考慮對於每個因數找到他所有倍數的編號,每次詢問之後先二分出 \(l\) 的位置,然後往後暴力刪除。單點修改和區間求和用樹狀陣列就可以了。

但是這樣子中間的被除過之後不是 \(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;
}