Comet OJ - Contest #11 D(kruskal重構樹)

題目鏈接: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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章