题意
你需要支持对一张 n 个点 m 条边点带权的无向连通图进行以下两种操作:
1、修改点 x 的点权。
2、询问从点 x 出发只经过编号不大于 y 的点能到达的所有点的点权之积取模 998244353
题解
对操作分块,每块内的答案一起求
求解时,按编号从小到大加入图中,维护所有联通块的点权的乘积
每次加完一个点,遍历和这个点有关的操作2,初始答案就是询问点所在的联通块的点权乘积
但是有修改
每次得到一个初始答案时,从块的起点开始遍历操作1,这些操作中,对当前答案有影响的,其修改的点所在的联通块必定和求解的点在一起,然后就更新一下答案即可
坑点是,点权的取值可以大于模数,就是说,当点权为998244353时,求的是0的逆元,是不存在的,所以要特殊处理一下
代码
#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-5
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
int fa[N],a[N],la[N],ans[N],qe[N],num[N],cnt,n,m,Q;
LL inv[N],s[N];
struct cc{int x,y; }G[N<<1];
inline void add(int x,int y){G[++cnt]={y,la[x]}; la[x]=cnt;}
struct node{
int op,x,y;
}q[N];
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
//fread->read
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
//fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void print(char *s){while (*s)out(*s++);}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void print(char *s){Ostream.print(s);}
};
using namespace IO;
int getfa(int x){
return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
inline void UNI(int a,int b){
int i=getfa(a),j=getfa(b);
if (i!=j)
{
fa[i]=j;
s[j]=s[j]*s[i]%mod;
num[j]+=num[i];
}
}
inline LL qpow(LL a,LL b){
LL res=1;
while(b){
if (b&1) res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
inline void slove(int st,int ed){
vector<pp> v[N]; int cnt=0;
for(int i=1;i<=n;i++)
{
fa[i]=i;
if (a[i]) s[i]=a[i],num[i]=0;
else num[i]=s[i]=1;
}
for(int i=st;i<=ed;i++) if (q[i].op==1)
if (q[i].x<=q[i].y) v[q[i].y].pb(pp(q[i].x,i));else;
else{
inv[i]=qpow(a[q[i].x],mod-2),a[q[i].x]=q[i].y, qe[++cnt]=i;
}
for(int i=1;i<=n;i++){
for(int j=la[i];j;j=G[j].y) UNI(i,G[j].x);
for(auto j:v[i]){
int t=getfa(j.fi);
LL tmp=s[t],tt=num[t];
for(int k=1;k<=cnt&&qe[k]<j.se;k++) if (getfa(q[qe[k]].x)==t)
{
if (inv[qe[k]]==0) tt--; else tmp=tmp*inv[qe[k]]%mod;
if (q[qe[k]].y) tmp=tmp*q[qe[k]].y%mod; else tt++;
}
if (tt) ans[j.se]=0; else ans[j.se]=tmp;
}
}
}
int main(int argc, char const *argv[]){
read(n);read(m);read(Q);
for(int i=1;i<=n;i++) read(a[i]),a[i]%=mod;
for(int i=1;i<=m;i++){
int x,y; read(x); read(y); if (x==y) continue; if (x<y) swap(x,y);
add(x,y);
}
for(int i=1;i<=Q;i++) read(q[i].op), read(q[i].x), read(q[i].y),q[i].y%=mod;
int block=min(sqrt(Q)*5,1.0*Q);
for(int i=1;i<=Q;i+=block) slove(i,min(i+block-1,Q));
for(int i=1;i<=Q;i++) if (q[i].op==1)
print(ans[i]%mod),Ostream.out('\n');
return 0;
}