题意:给出一幅图和每个点的权值,每次修改某个点权值或询问两点间所有简单路径上的点权值最小值
思路:
只能看出来tarjan缩点和树剖,然后完全未考虑清楚细节。。似乎建图方法很高级
首先tarjan缩点,对于每个块,新建一个点x,x向所有块内不是深度最小的点连边(借鉴(抄袭)某神犇的方法),然后深度最小的点向x连边,然后x的权值为所有块内不是深度最小的点的权值的最小值,然后询问时如果lca是新建点(序号>n)那就还要跟其父亲节点权值取min,修改时也要修改父亲节点(必定为新建点)的值,然后每个新建点可以用multiset(第一次用,好高级)维护块内(除掉某个点)的最小值。。
注意缩点姿势比较神奇(深度最小的点不要退栈啊!)
代码:
#include <bits/stdc++.h>
#define gc getchar()
#define N 200009
#define M 200009
#define mid (l+r>>1)
#define root 1,1,cnt
#define lson cur<<1,l,mid
#define rson cur<<1|1,mid+1,r
#define lc cur<<1
#define rc cur<<1|1
using namespace std;
typedef multiset<int>::iterator ptr;
int n,m,Q,x,y,first[N],number=1;
int Number,First[N<<1],rt;
int top,cnt,taj,vis[N<<1],size[N<<1];
int num[N<<1],deep[N<<1],Top[N<<1],father[N<<1],Mson[N<<1];
int dfn[N<<1],low[N],sta[M],val[N],Id[N];
int v[N<<3];
multiset<int> q[N<<3];
struct edge
{
int from,to,next;
void add(int x,int y)
{
from=x,to=y,next=first[x],first[x]=number;
}
}e[N<<1];
struct Edge
{
int to,next;
void add(int x,int y)
{
to=y,next=First[x],First[x]=Number;
}
}E[N<<3];
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-48;
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
return x*s;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
sta[++top]=x;
for (int i=first[x];i;i=e[i].next)
if (!dfn[e[i].to])
{
tarjan(e[i].to);
low[x]=min(low[x],low[e[i].to]);
if (low[e[i].to]>=dfn[x])
{
++taj;
father[taj]=x;
E[++Number].add(x,taj);
do
{
y=sta[top--];
father[y]=taj;
E[++Number].add(taj,y);
q[taj].insert(val[y]);
}while (y!=e[i].to);
}
}
else low[x]=min(low[x],dfn[e[i].to]);
}
void dfs1(int x)
{
size[x]=1;
deep[x]=deep[father[x]]+1;
for (int i=First[x];i;i=E[i].next)
{
dfs1(E[i].to);
size[x]+=size[E[i].to];
if (size[E[i].to]>size[Mson[x]]) Mson[x]=E[i].to;
}
}
void dfs2(int x,int y)
{
Top[x]=y;
dfn[x]=++cnt;
Id[cnt]=x;
if (Mson[x]) dfs2(Mson[x],y);
for (int i=First[x];i;i=E[i].next)
if (E[i].to!=Mson[x]) dfs2(E[i].to,E[i].to);
}
void build(int cur,int l,int r)
{
if (l==r)
{
v[cur]=val[Id[l]];
return;
}
build(lson);
build(rson);
v[cur]=min(v[lc],v[rc]);
}
void ins(int cur,int l,int r,int x,int y)
{
if (l==r)
{
v[cur]=y;
return;
}
if (x<=mid) ins(lson,x,y);
else ins(rson,x,y);
v[cur]=min(v[lc],v[rc]);
}
int qry(int cur,int l,int r,int L,int R)
{
if (L<=l&&R>=r) return v[cur];
int ans=1000000000;
if (L<=mid) ans=min(ans,qry(lson,L,R));
if (R>mid) ans=min(ans,qry(rson,L,R));
return ans;
}
int qry(int x,int y)
{
int ans=1000000000;
for (;Top[x]!=Top[y];x=father[Top[x]])
{
if (deep[Top[x]]<deep[Top[y]]) swap(x,y);
ans=min(ans,qry(root,dfn[Top[x]],dfn[x]));
}
if (dfn[x]>dfn[y]) swap(x,y);
ans=min(ans,qry(root,dfn[x],dfn[y]));
int lca=(dfn[x]<dfn[y])?x:y;
if (lca>n) ans=min(ans,val[father[lca]]);
return ans;
}
int getroot(int x)
{
return father[x]?getroot(father[x]):x;
}
int main()
{
memset(First,0,sizeof(First));
n=read(),m=read(),Q=read();
for (int i=1;i<=n;i++) val[i]=read();
for (int i=1;i<=m;i++)
{
x=read(),y=read();
e[++number].add(x,y),e[++number].add(y,x);
}
taj=n;
tarjan(1);
memset(dfn,0,sizeof(dfn));
cnt=0;
rt=getroot(1);
dfs1(rt);
dfs2(rt,rt);
for (int i=n+1;i<=taj;i++)
val[i]=*q[i].begin();
build(root);
for (int i=1;i<=Q;i++)
{
char ch;
while (ch=gc,ch!='A'&&ch!='C');
x=read(),y=read();
if (ch=='C')
{
if (father[x])
q[father[x]].erase(q[father[x]].find(val[x]));
ins(root,dfn[x],y);
val[x]=y;
if (father[x])
{
q[father[x]].insert(y);
val[father[x]]=*q[father[x]].begin();
ins(root,dfn[father[x]],val[father[x]]);
}
}
else printf("%d\n",qry(x,y));
}
return 0;
}