[CodeForces 487E]Tourists

Link

Description

\(n\)个点,\(m\)条边的无向连通图,每个点有点权。

有两种操作:

  • 修改某个点的点权。
  • 询问两点间所有简单路径上点权最小值。

Solution

建出圆方树。令方点点权为相邻圆点点权的最小值。那么现在询问就变成查询路径最小值,可以用树剖+线段树解决。

对于修改,如果修改某个点权值,那么它周围的所有方点权值都要修改,可以被卡成\(\text O(n)\)

所以改一下思路,考虑到圆方树是一棵树,可以令方点点权为其儿子圆点点权的最小值。这样,修改一个圆点,只需要顺带修改其父亲方点的点权即可。

对于每方点,用一个multiset维护所有儿子圆点的权值。

值得注意的是,如果查询时两点lca是方点,那还要查询其父亲圆点的权值。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){//be careful for long long!
    register int x=0,f=1;register char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
    return f?x:-x;
}
 
const int N=1e5+10;
int n,m,q,w[N<<1],cnt,dfc,dfn[N<<1],low[N],stk[N],tp;
vector<int> re_E[N],E[N<<1];
#define pb(x) push_back(x)
 
inline void Tarjan(int nw){
    dfn[nw]=low[nw]=++dfc;stk[++tp]=nw;
    for(int to:re_E[nw])
    if(!dfn[to]){
        Tarjan(to);
        low[nw]=min(low[nw],low[to]);
        if(low[to]==dfn[nw]){
        ++cnt;
        for(int x=0;x^to;--tp){
            x=stk[tp];
            E[x].pb(cnt),E[cnt].pb(x);
        }
        E[nw].pb(cnt),E[cnt].pb(nw);
        }
    }
    else low[nw]=min(low[nw],dfn[to]);
}
 
namespace TCP{
    const int _=2e5+10;
    int son[_],siz[_],fa[_],dep[_],tp[_],rol[_];
    multiset<int> W[_>>1];
    struct Segment_tree{
#define ls(p) p<<1
#define rs(p) p<<1|1
    int tr[_<<2];
    inline void update(int p){tr[p]=min(tr[ls(p)],tr[rs(p)]);return;}
    inline void Build(int p,int l,int r){
        if(l==r){tr[p]=w[rol[l]];return;}
        int mid=(l+r)>>1;
        Build(ls(p),l,mid),Build(rs(p),mid+1,r);
        update(p);
    }
    inline void Modify(int p,int l,int r,int pos,int val){
        if(l==r){tr[p]=val;return;}
        int mid=(l+r)>>1;
        if(mid>=pos)Modify(ls(p),l,mid,pos,val);
        else Modify(rs(p),mid+1,r,pos,val);
        update(p);
    }
    inline int Query(int p,int l,int r,int L,int R){
        if(L<=l&&r<=R)return tr[p];
        int mid=(l+r)>>1,ans=2e9;
        if(mid>=L)ans=min(ans,Query(ls(p),l,mid,L,R));
        if(mid<R)ans=min(ans,Query(rs(p),mid+1,r,L,R));
        return ans;
    }
    }T;
 
    inline void Dfs_o(int nw,int f=0){
    siz[nw]=1;dep[nw]=dep[fa[nw]]+1;
    for(int to:E[nw])
        if(to^f){
        fa[to]=nw;Dfs_o(to,nw);siz[nw]+=siz[to];
        if(siz[to]>siz[son[nw]])son[nw]=to;
        if(nw>n)W[nw-n].insert(w[to]);
        }
    }
    inline void Dfs_t(int nw){
    dfn[nw]=++dfc;rol[dfc]=nw;
    if(!tp[nw])tp[nw]=nw;
    if(son[nw]){tp[son[nw]]=tp[nw];Dfs_t(son[nw]);}
    for(int to:E[nw])
        if(to^fa[nw]&&to^son[nw])
        Dfs_t(to);
    }
    inline int lca(int x,int y){
    int ans=0x7fffffff;
    while(tp[x]^tp[y]){
        if(dep[tp[x]]>=dep[tp[y]])ans=min(ans,T.Query(1,1,dfc,dfn[tp[x]],dfn[x])),x=fa[tp[x]];
        else ans=min(ans,T.Query(1,1,dfc,dfn[tp[y]],dfn[y])),y=fa[tp[y]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=min(ans,T.Query(1,1,dfc,dfn[x],dfn[y]));
    if(x>n)ans=min(ans,w[fa[x]]);
    return ans;
    }
}using namespace TCP;
 
int main(){
    n=cnt=read(),m=read(),q=read();
    for(int i=1;i<=n;++i)w[i]=read();
    for(int i=1,u,v;i<=m;++i)u=read(),v=read(),re_E[u].pb(v),re_E[v].pb(u);
    Tarjan(1);memset(dfn,0,sizeof(dfn));dfc=0;
    Dfs_o(1),Dfs_t(1);
    for(int i=n+1;i<=dfc;++i)w[i]=(*W[i-n].begin());
    T.Build(1,1,dfc);
    while(q--){
    char ch=getchar();
    switch(ch){
    case 'C':{
        int x=read();
        if(x^1){
        W[fa[x]-n].erase(W[fa[x]-n].find(w[x]));
        W[fa[x]-n].insert(w[x]=read());
        T.Modify(1,1,dfc,dfn[fa[x]],(*W[fa[x]-n].begin()));
        }
        else w[x]=read();
        T.Modify(1,1,dfc,dfn[x],w[x]);
        break;
    }
    case 'A':{
        int x=read(),y=read();
        printf("%d\n",TCP::lca(x,y));
        break;
    }
    }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fruitea/p/12080439.html