题目大意
给定一个有
n
个点
有
q
个操作,每次询问所有点
题目分析
第一眼看见这题应该有个很显然的想法,就是点双连通分量缩点然后树链剖分。
但是实际想一想,细节还是很多的,怎样构图才能保证正确性而且修改的时候不会T?
在这里我们使用这样一种方法:对于每一个点双连通分量,我们建一个新建点储存点双所有点的最小权值,然后该点向点双内所有
不是深度最小的点
连一条边,然后深度最小的点(大多情况为割点,当然树根不一定是割点)向这个新建点连边。
注意到这棵树一定是普通点连向新建点连向普通点这样交替。修改的时候我们修改这个点自身的权值,还要把这个点所属的新建点(父亲节点)修改了。查询的时候呢?首先先查询两点之间路径的最小值,然后如果两点
LCA
是新建点,那就还要查询它的父亲的最小值更新。
为什么这样是对的呢?因为查询的时候,除了最顶端
LCA
所在的点双,其它点的点双的顶点都是肯定能够经过的,查询是不会出错的,最顶端的
LCA
如果是一个新建点,那么就证明我还是可以通过该点双的顶点的,但是我没有用这个顶点更新过点双,因此要再用这个顶点(即
LCA
父亲)更新一下答案。否则这是一个顶点,如果我要经过该点双其它位置,那么必然要经过顶点两次,那是不行的,因此不用管。
关于怎么维护点双内最小值,对每一个新建点开一个
multiset
就好了。
时间复杂度
O(nlog22n)
。
代码实现
#include <algorithm>
#include <iostream>
#include <climits>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <stack>
#include <set>
using namespace std;
typedef multiset<int>::iterator ptr;
const int INF=INT_MAX;
const int N=100050;
const int V=N<<1;
const int M=N<<1;
const int E=M<<1;
const int EL=V<<1;
const int LGEL=19;
multiset<int> bst[V];
struct G
{
int next[E],tov[E];
int last[V];
int tot;
void insert(int x,int y){tov[++tot]=y,next[tot]=last[x],last[x]=tot;}
}g,t;
int size[V],hea[V],prt[V],fa[V],DFN[V],LOW[N],val[V],high[V],pos[V];
int n,m,q,all,idx,el,lgel;
int rmq[EL][LGEL];
int euler[EL];
stack<int> S;
struct segment_tree
{
int v[V<<2];
void update(int x){v[x]=min(v[x<<1],v[x<<1|1]);}
void modify(int x,int y,int l,int r,int edit)
{
if (l==r)
{
v[x]=edit;
return;
}
int mid=l+r>>1;
if (y<=mid) modify(x<<1,y,l,mid,edit);
else modify(x<<1|1,y,mid+1,r,edit);
update(x);
}
int query(int x,int st,int en,int l,int r)
{
if (st==l&&en==r) return v[x];
int mid=l+r>>1;
if (en<=mid) return query(x<<1,st,en,l,mid);
else if (mid+1<=st) return query(x<<1|1,st,en,mid+1,r);
else return min(query(x<<1,st,mid,l,mid),query(x<<1|1,mid+1,en,mid+1,r));
}
}T;
void tarjan(int x,int fr)
{
DFN[x]=LOW[x]=++idx,S.push(x);
for (int i=g.last[x],y;i;i=g.next[i])
if (!DFN[y=g.tov[i]])
{
tarjan(y,x);
LOW[x]=min(LOW[x],LOW[y]);
if (LOW[y]>=DFN[x])
{
int sp=++all;
t.insert(x,sp);
for (int u;;)
{
u=S.top(),S.pop(),t.insert(sp,u),bst[sp].insert(val[u]);
if (u==y) break;
}
}
}
else if (y!=fr) LOW[x]=min(LOW[x],DFN[y]);
}
void dfs(int x)
{
size[x]=1,hea[x]=0,rmq[pos[euler[++el]=x]=el][0]=x;
for (int i=t.last[x],y;i;i=t.next[i])
{
high[y=t.tov[i]]=high[x]+1,fa[y]=x,dfs(y),euler[++el]=x,rmq[el][0]=x,size[x]+=size[y];
if (!hea[x]||size[hea[x]]<size[y]) hea[x]=y;
}
}
void build(int x,int fr)
{
DFN[x]=++idx,prt[x]=fr;
if (!hea[x]) return;
build(hea[x],fr);
for (int i=t.last[x],y;i;i=t.next[i])
if ((y=t.tov[i])!=hea[x]) build(y,y);
}
void pre()
{
lgel=trunc(log(el)/log(2));
for (int j=1;j<=lgel;j++)
for (int i=1;i+(1<<j)-1<=el;i++)
rmq[i][j]=high[rmq[i][j-1]]<high[rmq[i+(1<<j-1)][j-1]]?rmq[i][j-1]:rmq[i+(1<<j-1)][j-1];
for (int i=n+1;i<=all;i++) val[i]=*bst[i].begin();
for (int i=1;i<=all;i++) T.modify(1,DFN[i],1,idx,val[i]);
}
int getrmq(int l,int r)
{
int lgr=trunc(log(r-l+1)/log(2));
return high[rmq[l][lgr]]<high[rmq[r-(1<<lgr)+1][lgr]]?rmq[l][lgr]:rmq[r-(1<<lgr)+1][lgr];
}
int lca(int x,int y)
{
if ((x=pos[x])>(y=pos[y])) swap(x,y);
return getrmq(x,y);
}
int getans(int x,int y)
{
int z=lca(x,y),ret=INF;
for (int u=prt[x];prt[x]!=prt[z];x=fa[u],u=prt[x]) ret=min(ret,T.query(1,DFN[u],DFN[x],1,idx));
ret=min(ret,T.query(1,DFN[z],DFN[x],1,idx));
for (int u=prt[y];prt[y]!=prt[z];y=fa[u],u=prt[y]) ret=min(ret,T.query(1,DFN[u],DFN[y],1,idx));
ret=min(ret,T.query(1,DFN[z],DFN[y],1,idx));
if (z>n) ret=min(ret,val[fa[z]]);
return ret;
}
int main()
{
freopen("tourists.in","r",stdin),freopen("tourists.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++) scanf("%d",&val[i]);
for (int i=1,u,v;i<=m;i++)
{
scanf("%d%d",&u,&v);
g.insert(u,v),g.insert(v,u);
}
all=n,tarjan(1,0),high[1]=1,fa[1]=0,dfs(1),idx=0,memset(DFN,0,sizeof DFN),build(1,1),pre();
for (int i=1,a,b;i<=q;i++)
{
char opt=getchar();
while (!isalpha(opt)) opt=getchar();
scanf("%d%d",&a,&b);
if (opt=='C')
{
if (fa[a]) bst[fa[a]].erase(bst[fa[a]].find(val[a]));
val[a]=b,T.modify(1,DFN[a],1,idx,val[a]);
if (fa[a]) bst[fa[a]].insert(val[a]),val[fa[a]]=*bst[fa[a]].begin(),T.modify(1,DFN[fa[a]],1,idx,val[fa[a]]);
}
else printf("%d\n",getans(a,b));
}
fclose(stdin),fclose(stdout);
return 0;
}