洛谷 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;
}
标签:include,洛谷,fa,int,Ynoi2013,ts,leq,fd,P5610 来源: https://www.cnblogs.com/sdlang/p/14263720.html