从大到小枚举 x,每次把 w_i=x 的点作为起点dfs,然后记录每个询问 x 的答案,就可以回答询问啦!
你当这题没有修改吗???
事实上,修改造成的影响只有 w_c<x,w_c\ge x 两种,所以分两种情况,ans[0][x] 表示 w_c<x 时询问 x 的答案,ans[1][x] 表示 w_c\ge x 时询问 x 的答案。计算 ans[0][x] 时跳过 c,计算 ans[1][x] 时先以 c 为起点dfs再dfs其它点。
总复杂度:O(n+q)
等等?排序呢???
值得注意的是,vector/前向星常数可能较大。由于每个点最多只连两条边,可以用两个数组分别存向左/向右的边。同时最好不要用vector/前向星来作为桶排序的容器。
当然,~~ctr非常良心~~,实测前向星存图+前向星桶排~~只需~~$2.7s$,是可过的。两个数组存图+`std::sort`也只需 $1.8s$。
### 参考代码:
```cpp
#include <cstdio>
#include <cstring>
const int N=2000010;
void dfs(int u);
unsigned long long seed;
int n, m, c, mfq, mind, maxd, k, w[2000001], d[2000001];
int sta[N],top,tot,ans[2][N],l[N],r[N],ord[N],cnt[N];
bool vis[N];
inline int randInt() { seed = 99999989 * seed + 1000000007; return seed >> 33; }
void generate()
{
for (int i = 1; i <= n; i++) { w[i] = randInt() % n; }
for (int i = 1; i <= n; i++) { d[i] = randInt() % (maxd - mind + 1) + mind; }
}
void getOperation(int lastans, int &opt, int &x)
{
if ((0ll + randInt() + lastans) % mfq) { opt = 1; } else { opt = 2; }
x = (0ll + randInt() + lastans) % n;
}
int main()
{
int i,j,lxl;
scanf("%d %d %d", &n, &m, &c);
scanf("%llu %d %d %d %d", &seed, &mind, &maxd, &mfq, &k);
generate();
for (int i = 1; i <= k; i++)
{
int p, t;
scanf("%d %d", &p, &t);
d[p] = t;
}
lxl=w[c]; //lxl表示当前绫小路的能力值
for (i=1;i<=n;++i) //连边
{
while (top&&sta[top]+d[sta[top]]<i)
{
--top;
}
if (top)
{
l[i]=sta[top];
}
sta[++top]=i;
}
top=0;
for (i=n;i>=1;--i)
{
while (top&&sta[top]-d[sta[top]]>i)
{
--top;
}
if (top)
{
r[i]=sta[top];
}
sta[++top]=i;
}
for (i=1;i<=n;++i) //计数排序
{
++cnt[w[i]];
}
for (i=n-1;i>=0;--i)
{
cnt[i]+=cnt[i+1];
}
for (i=1;i<=n;++i)
{
ord[--cnt[w[i]]]=i;
}
for (i=n-1,j=0;i>=0;--i) //计算ans[0][i]
{
while (j<n&&w[ord[j]]==i)
{
if (ord[j]!=c)
{
dfs(ord[j]);
}
++j;
}
ans[0][i]=tot;
}
tot=0;
memset(vis,false,sizeof(vis));
dfs(c);
for (i=n-1,j=0;i>=0;--i) //计算ans[1][i]
{
while (j<n&&w[ord[j]]==i)
{
if (ord[j]!=c)
{
dfs(ord[j]);
}
++j;
}
ans[1][i]=tot;
}
int lastans = 0, finalans = 0;
for (i = 1; i <= m; i++)
{
int opt, x;
getOperation(lastans, opt, x);
if (opt == 1)
{
finalans = (finalans * 233ll + ans[lxl>=x][x]) % 998244353;
lastans = ans[lxl>=x][x];
}
else
{
lxl=x;
}
}
printf("%d\n", finalans);
return 0;
}
void dfs(int u)
{
if (vis[u]||u==0)
{
return;
}
vis[u]=true;
++tot;
dfs(l[u]);
dfs(r[u]);
}
```