题意:给一个无向连通图,两种操作:1.修改点权 2.询问从x出发只经过编号<=y 的点的点权积
按边端点的max值排序后建kruscal重构树,线段树维护重构树dfs序的点权积,修改时的直接线段树单点修改点权,查询时倍增找到x能到达的最高结点查询子树的点积即可。。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
struct Q{
int a,b,c;
}A[200100];
int p[200010],B[200010],ll[200010],rr[200010],C[200010],dfn=0,fa[200010][30];
vector<int>g[200010];
int f(int a){
if(p[a]==a) return a;
p[a]=f(p[a]);
return p[a];
}
int cmp(Q a,Q b){
return a.c<b.c;
}
void dfs(int u,int f){
int i,v;
ll[u]=++dfn;
fa[u][0]=f;
for(i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
for(i=0;i<g[u].size();i++){
v=g[u][i];
if(v!=f) dfs(v,u);
}
rr[u]=dfn;
}
long long T[1000000],mo=998244353;
void update(int root,int l,int r,int k,long long v){
if(l==r){
T[root]=v%mo;
return;
}
int mid=(l+r)/2;
if(k<=mid) update(root*2,l,mid,k,v);
else update(root*2+1,mid+1,r,k,v);
T[root]=T[root*2]*T[root*2+1]%mo;
}
long long qsum(int root,int l,int r,int L,int R){
if(l==L&&r==R) return T[root];
int mid=(l+r)/2;
if(R<=mid) return qsum(root*2,l,mid,L,R);
else if(L>mid) return qsum(root*2+1,mid+1,r,L,R);
else return qsum(root*2,l,mid,L,mid)*qsum(root*2+1,mid+1,r,mid+1,R)%mo;
}
int main(){
int i,n,m,q,a,b,k;
for(i=1;i<=2e5;i++) p[i]=i;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;i++) scanf("%d",&C[i]);
for(i=1;i<=m;i++){
scanf("%d%d",&A[i].a,&A[i].b);
A[i].c=max(A[i].a,A[i].b);
}
sort(A+1,A+m+1,cmp);
int cnt=n;
for(i=1;i<=m;i++){
a=f(A[i].a);
b=f(A[i].b);
if(a!=b){
cnt++;
g[cnt].push_back(a);
g[cnt].push_back(b);
g[a].push_back(cnt);
g[b].push_back(cnt);
B[cnt]=A[i].c;
p[a]=p[b]=cnt;
C[cnt]=1;
}
}
dfs(cnt,0);
for(i=1;i<=cnt;i++) update(1,1,cnt,ll[i],C[i]);
while(q--){
scanf("%d%d%d",&k,&a,&b);
if(k==2) update(1,1,cnt,ll[a],b);
else{
if(a>b){
printf("0\n");
continue;
}
for(i=20;i>=0;i--) if(fa[a][i]&&B[fa[a][i]]<=b) a=fa[a][i];
printf("%lld\n",qsum(1,1,cnt,ll[a],rr[a])%mo);
}
}
return 0;
}