[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;
}

posted @ 2019-12-22 17:43  Fruitea  阅读(170)  评论(0编辑  收藏  举报