题目链接:http://uoj.ac/problem/30
题目大意:给定一张无向连通图,每个点有点权,多次询问两个点之间的简单路径上最小点权值的最小值
首先求的是最小点权值的最小值 那么我们肯定要走点权越小的点越好 但是由于求的是简单路径 那么我们就不能经过同一个点两次
那么我们Tarjan求点双联通分量 每个点双维护一个最小值 那么答案显然就是两点所在点双路径上的最小值 树链剖分即可 (正确性我不会证
但是一个割点可以属于多个点双 因此割点在计算距离的时候要取最近的那个点双 建图时对于每一个割点建一个权值为+∞的虚点连向所有所在的点双即可
那么问题来了:由于一个割点可以属于多个点双 那么修改一个点的权值就要更新多个点双 如果这个图是一朵菊花 那么岂不直接被卡到O(n^2)?
因此 对于每个割点 我们只用这个割点所在虚点的父亲点双来维护这个点
如果所求的两个点的LCA是虚点 那么就统计这个虚点所代表的点的点权 如果LCA是点双 那么就把这个点双的父亲节点加入统计
然后基本就可以了 Tarjan求点双容易写挂 注意一下
看到神犇们的代码7KB+着实吓了一跳&…… 写完发现只有4KB…… 结果我第一,又快又好写……
#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define INF 0x3f3f3f3f
using namespace std;
struct BCC{
multiset<int>s;
int value;
inline void Insert(int x)
{
s.insert(x);
value=*s.begin();
}
inline void Modify(int x,int y)
{
s.erase( s.find(x) );
s.insert(y);
value=*s.begin();
}
}BCCs[M<<1];
namespace ZKW_Segtree{
int tree[263000<<1]={INF};
int q;
void Build_Tree(int a[],int n)
{
int i;
for(q=1;q<=n+1;q<<=1);
for(i=1;i<=n;i++)
tree[q+i]=a[i];
for(i=q-1;i;i--)
tree[i]=min(tree[i<<1],tree[i<<1|1]);
}
void Modify(int x,int y)
{
tree[x+=q]=y;
while(x>>=1)
tree[x]=min(tree[x<<1],tree[x<<1|1]);
}
int Get_Ans(int x,int y)
{
int re=INF;
for(x+=q-1,y+=q+1;x^y^1;x>>=1,y>>=1)
{
if(~x&1) re=min(re,tree[x^1]);
if( y&1) re=min(re,tree[y^1]);
}
return re;
}
}
int n,m,q,cnt;
int a[M],belong[M];
bool v[M];
namespace New_Map{
struct abcd{
int to,next;
}table[M<<2];
int head[M<<1],tot;
int fa[M<<1],son[M<<1],dpt[M<<1],size[M<<1],top[M<<1],pos[M<<1],posf[M<<1],T;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void DFS1(int x)
{
int i;
size[x]=1;
dpt[x]=dpt[fa[x]]+1;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x])
{
fa[table[i].to]=x;
DFS1(table[i].to);
size[x]+=size[table[i].to];
if(size[table[i].to]>size[son[x]])
son[x]=table[i].to;
}
}
void DFS2(int x)
{
int i;
if(son[fa[x]]==x)
top[x]=top[fa[x]];
else
top[x]=x;
posf[pos[x]=++T]=BCCs[x].value;
if(son[x])
DFS2(son[x]);
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x]&&table[i].to!=son[x])
DFS2(table[i].to);
}
int LCA(int x,int y)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dpt[fx]<dpt[fy])
swap(x,y),swap(fx,fy);
x=fa[fx];fx=top[x];
}
if(dpt[x]<dpt[y])
swap(x,y);
return y;
}
void Make_Graph()
{
int i;
memset(posf,0x3f,sizeof posf);
DFS1(n+1);DFS2(n+1);
ZKW_Segtree::Build_Tree(posf,T);
}
int Query(int x,int y)
{
int re,fx=top[x],fy=top[y],temp=LCA(x,y);
if(temp<=cnt) temp=fa[temp];re=a[temp-n];
while(fx!=fy)
{
if(dpt[fx]<dpt[fy])
swap(x,y),swap(fx,fy);
re=min(re,ZKW_Segtree::Get_Ans(pos[fx],pos[x]));
x=fa[fx];fx=top[x];
}
if(dpt[x]<dpt[y])
swap(x,y);
re=min(re,ZKW_Segtree::Get_Ans(pos[y],pos[x]));
return re;
}
}
namespace Ori_Map{
struct abcd{
int to,next;
}table[M<<1];
int head[M],tot;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void Tarjan(int x)
{
static int stack[M],top;
static int dpt[M],low[M],T;
int i;
dpt[x]=low[x]=++T;
stack[++top]=x;
for(i=head[x];i;i=table[i].next)
{
if(dpt[table[i].to])
low[x]=min(low[x],dpt[table[i].to]);
else
{
Tarjan(table[i].to);
low[x]=min(low[x],low[table[i].to]);
if(dpt[x]==low[table[i].to])
{
int t;++cnt;
v[x]=1;
do{
t=stack[top--];
belong[t]=cnt;
if(v[t])
{
New_Map::Add(t+n,cnt);
New_Map::Add(cnt,t+n);
}
}while(t!=table[i].to);
New_Map::Add(x+n,cnt);
New_Map::Add(cnt,x+n);
}
}
}
}
inline void Make_Graph()
{
int i;
Tarjan(1);
for(i=1;i<=n;i++)
{
if(i!=1)
BCCs[ belong[i] ].Insert(a[i]);
if(v[i]) BCCs[i+n].Insert(INF);
}
New_Map::Make_Graph();
}
}
int main()
{
//freopen("30.in","r",stdin);
//freopen("30.out","w",stdout);
int i,x,y;
char p[10];
cin>>n>>m>>q;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=m;i++)
scanf("%d%d",&x,&y),Ori_Map::Add(x,y),Ori_Map::Add(y,x);
Ori_Map::Make_Graph();
for(i=1;i<=q;i++)
{
scanf("%s%d%d",p,&x,&y);
if(p[0]=='C')
{
if(x!=1)
{
BCCs[belong[x]].Modify(a[x],y);
ZKW_Segtree::Modify(New_Map::pos[belong[x]],BCCs[belong[x]].value);
}
a[x]=y;
}
else
{
if(x==y)
{
printf("%d\n",a[x]);
continue;
}
x=v[x]?x+n:belong[x];
y=v[y]?y+n:belong[y];
printf("%d\n", New_Map::Query(x,y) );
}
}
return 0;
}