题目链接:https://www.cometoj.com/contest/67/problem/D?problem_id=3801
思路:以边链接两点的最大值为权值,建立kruscal重构树,然后线段树随便搞一搞就好
下面是kruscal重构树的一些性质:
1.(只考虑新节点)根据以下的构造过程,kruskal重构树是一颗二叉树,并符合二叉堆的性质。
2.原树两点间的的最大边权就是kruskal重构树上两点的lca的权值。
3.重构树中代表原树中的点的节点全是叶子节点,其余节点都代表了一条边的边权。
4. kruskal的每个子树是原图上保留边权不大于根节点权值的边后的极大连通子图。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-6
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
int n,m,q,qw,zz,dl[200008],dr[200008],op,x,y,fa[200008][20],id[200008],dd[200008];
ll b[200008];
vector<int>g[200008];
struct as{
int u,v,d;}a[200008];
bool cmp(as a,as b) {return a.d<b.d;}
int fid(int x)
{
int a=x,b;
while(fa[a][0]!=a) a=fa[a][0];
while(x!=a) b=fa[x][0],fa[x][0]=a,x=b;
return a;
}
void dfs(int u,int f)
{
dl[u]=++zz;fa[u][0]=f;dd[zz]=b[u];
for(int i=0;i<g[u].size();i++) dfs(g[u][i],u);
dr[u]=zz;
}
struct asa{
int l,r;
ll ma;
}tr[200008<<2];
void push(int d){tr[d].ma=tr[lc].ma*tr[rc].ma%mod;}
void build(int d,int l,int r)
{
tr[d].l=l,tr[d].r=r;
if(l==r) {tr[d].ma=dd[l];return;}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push(d);
}
void add(int d,int l,int pos)
{
if(tr[d].l==tr[d].r&&tr[d].l==l) {tr[d].ma=pos;return;}
int mid=(tr[d].l+tr[d].r)>>1;
if(mid>=l) add(lc,l,pos);
else add(rc,l,pos);
push(d);
}
ll query(int d,int l,int r)
{
if(tr[d].l==l&&tr[d].r==r) {return tr[d].ma;}
int mid=(tr[d].l+tr[d].r)>>1;
if(mid>=r) return query(lc,l,r);
else if(l>mid) return query(rc,l,r);
else return query(lc,l,mid)*query(rc,mid+1,r)%mod;
}
void bz()
{
FOR(i,1,18)
FOR(j,1,2*n-1)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
ll query(int x,int y)
{
FOL(i,18,0)
{
int f=fa[x][i];
if(id[f]<=y&&id[f]) x=f;
}
return query(1,dl[x],dr[x])%mod;
}
int main()
{
cin.tie(0);
cout.tie(0);
cin>>n>>m>>q;
qw=n;
FOR(i,1,n) sl(b[i]),fa[i][0]=i;
FOR(i,n+1,2*n-1) b[i]=1,fa[i][0]=i;
FOR(i,1,m)
{
si(a[i].u),si(a[i].v);
a[i].d=max(a[i].u,a[i].v);
}
sort(a+1,a+m+1,cmp);
FOR(i,1,m)
{
int fx=fid(a[i].u),fy=fid(a[i].v);
if(fx==fy) continue;
fa[fx][0]=fa[fy][0]=++qw;
id[qw]=a[i].d;
g[qw].pb(fx),g[qw].pb(fy);
if(qw==2*n-1) break;
}
dfs(qw,0);build(1,1,qw);bz();
while(q--)
{
si(op),si(x),si(y);
if(op==2) add(1,dl[x],y);
else if(x>y) puts("0");
else printf("%lld\n",query(x,y));
}
return 0;
}