题意:
你需要支持对一张 nn 个点 mm 条边点带权的无向连通图进行以下两种操作:
- 修改点 x 的点权。
- 询问从点 x 出发只经过编号不大于 y 的点能到达的所有点的点权之积取模 998244353。
题解:
新的知识点:kruskal重构树
这个东西可以把一张无向图重构成一棵树,然后就可以很方便的得到某个点只走边权不超过y的边可以到达的点的集合(得到dfs序上的一个区间),然后维护这个区间的答案就可以了。这道题里把边权设成两端点中编号较大的那个的编号。
维护一个区间乘积的线段树,支持单点修改。
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 1e6 + 50;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
ll a[maxn];
int n, m, q;
int fa[maxn], tot, f[maxn][20], val[maxn];
int dfn[maxn], idx, id[maxn], sz[maxn];
int fnd(int x) {if(x == fa[x]) return x; return fa[x] = fnd(fa[x]);}
struct node{
int u, v, w;
node(){}; node(int a, int b, int c):u(a), v(b), w(c){}
bool operator < (const node& a)const{return w < a.w;}
}e[maxn];
vector<int> g[maxn];
void mst(){//把图重构成树
tot = n;
sort(e, e+m);
for(int i = 0; i < m; ++i){
int u = fnd(e[i].u), v = fnd(e[i].v);
if(u == v) continue;
++tot;
fa[u] = fa[v] = tot;
g[tot].push_back(u);
g[tot].push_back(v);
val[tot] = e[i].w;
a[tot] = 1;
fa[tot] = tot;
}
}
void dfs(int u){
sz[u] = 1;
dfn[++idx] = u; id[u] = idx;
for(int i = 1; i < 20; ++i) f[u][i] = f[f[u][i-1]][i-1];
for(int i = 0; i < g[u].size(); ++i){
int v = g[u][i];
f[v][0] = u;
dfs(v); sz[u] += sz[v];
}
}
void init(){
idx = 0;
val[0] = inf;
cin>>n>>m>>q;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]), fa[i] = i;
for(int i = 0; i < m; ++i){
int u, v; scanf("%d%d", &u, &v);
e[i] = node(u, v, max(u, v));
}
mst();
dfs(tot);
}
ll sum[maxn<<2];
void up(int rt){
sum[rt] = sum[rt<<1]*sum[rt<<1|1]%mod;
}
void build(int rt, int l, int r){
if(l == r){
sum[rt] = a[dfn[l]]%mod; return;
}
build(lson); build(rson);
up(rt);
}
void update(int rt, int l, int r, int pos, ll x){
if(l == r){
sum[rt] = x; return;
}
if(pos <= mid) update(lson, pos, x);
else update(rson, pos, x);
up(rt);
}
ll qry(int rt, int l, int r, int L, int R){
if(L <= l && r <= R) return sum[rt];
ll ans = 1;
if(L <= mid) ans = ans*qry(lson, L, R)%mod;
if(R > mid) ans = ans*qry(rson, L, R)%mod;
return ans;
}
void sol()
{
build(1, 1, idx);
while(q--){
int op, x;
ll y;
scanf("%d%d%lld", &op, &x, &y);
if(op == 1){
if(x > y){
printf("0\n"); continue;
}
for(int i = 19; i >= 0; --i){
// cout<<f[x][i]<<endl;
if(val[f[x][i]] > y) continue;
//cout<<"x:"<<x<<endl;
x = f[x][i];
//cout<<"afterx:"<<x<<endl;
}
ll ans = qry(1, 1, idx, id[x], id[x] + sz[x] - 1);
printf("%lld\n", ans%mod);
}
else{
//assert(y != mod);
update(1, 1, idx, id[x], y%mod);//注意这里y可能等于mod,所以不要用逆元去代换,直接修改即可!
}
}
}
int main()
{
init();sol();
}