E. Tourists

time limit per test:

2 seconds

memory limit per test:

256 megabytes

input:

standard input

output

:standard output

There are n cities in Cyberland, numbered from 1 to n, connected by m bidirectional roads. The j-th road connects city aj and bj.

For tourists, souvenirs are sold in every city of Cyberland. In particular, city i sell it at a price of wi.

Now there are q queries for you to handle. There are two types of queries:

  • "C a w": The price in city a is changed to w.
  • "A a b": Now a tourist will travel from city a to b. He will choose a route, he also doesn't want to visit a city twice. He will buy souvenirs at the city where the souvenirs are the cheapest (possibly exactly at city a or b). You should output the minimum possible price that he can buy the souvenirs during his travel.

More formally, we can define routes as follow:

  • A route is a sequence of cities [x1, x2, ..., xk], where k is a certain positive integer.
  • For any 1 ≤ i < j ≤ k, xi ≠ xj.
  • For any 1 ≤ i < k, there is a road connecting xi and xi + 1.
  • The minimum price of the route is min(wx1, wx2, ..., wxk).
  • The required answer is the minimum value of the minimum prices of all valid routes from a to b.

Input

The first line of input contains three integers n, m, q (1 ≤ n, m, q ≤ 105), separated by a single space.

Next n lines contain integers wi (1 ≤ wi ≤ 109).

Next m lines contain pairs of space-separated integers aj and bj (1 ≤ aj, bj ≤ n, aj ≠ bj).

It is guaranteed that there is at most one road connecting the same pair of cities. There is always at least one valid route between any two cities.

Next q lines each describe a query. The format is "C a w" or "A a b" (1 ≤ a, b ≤ n, 1 ≤ w ≤ 109).

Output

For each query of type "A", output the corresponding answer.

Examples

input
3 3 3
1
2
3
1 2
2 3
1 3
A 2 3
C 1 5
A 2 3
output
1
2
input
7 9 4
1
2
3
4
5
6
7
1 2
2 5
1 5
2 3
3 4
2 4
5 6
6 7
5 7
A 2 3
A 6 4
A 6 7
A 3 3

output

2
1
5
3

Note

For the second sample, an optimal routes are:

From 2 to 3 it is [2, 3].

From 6 to 4 it is [6, 5, 1, 2, 4].

From 6 to 7 it is [6, 5, 7].

From 3 to 3 it is [3].

Solution

中文题面见UOJ#30  : UOJ#30

思路比较显然,把图缩点重建,再利用数据结构去维护。

要求简单路径,显然可以考虑点双连通分量,我们先对图Tarjan求点双连通分量,然后将这些BCC维护一个最小值,然后缩成一个点,这样就形成一棵树,就可以树剖。

但是这里有一个问题,割点可能会存在于多个点双连通分量中,而这会比较蛋疼,因为割点的答案显然应该是距离它最小的那个。

所以我们对割点单独处理,每个割点新建一个点单独向它所在的所有点双连通分量连一条边; 这样我们就可以在询问的时候,搞定割点的问题了。

那么修改一个点,这个点所在点双的值就有可能发生改变,如果修改割点,那么就会对很多点双造成影响,所以要特殊处理这种情况。

但是我们发现,我们这样建出来的新图(树)一定是满足 块->割点->块->割点 的。

所以我们不妨定义一个点双维护的是,这个点双中除了它fa的割点的所有点的权值+连向它的割点的权值最小,这样如果修改一个割点,就只会影响到它的fa点双。

查询的时候,我们查询$<u,v>$,如果$LCA(u,v)$是一个割点,我们可以直接统计答案。 如果$LCA(u,v)$是一个点双,那么我们还得查它的fa割点的值。

点双内的最小值,可以用multiset来维护。

这样的查询复杂度是$O(log^{2}N)$,修改的复杂度是$O(logN)$,总的复杂度就是$O(Nlog^{2}N)$

对于Tarjan点双连通分量,网上有些人说要边入栈,但很多人却写的点入栈,其实都是可以的。 但是这道题,如果用边入栈的方法,在连边的时候会连出问题的,需要额外判,所以就用来点入栈的方法。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<cstring>
using namespace std;
inline int read()
{
int x=; char ch=getchar();
while (ch<'' || ch>'') {ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x;
}
#define INF 0x7fffffff
#define MAXN 100100
int N,M,Q,val[MAXN],Val[MAXN<<];
struct RoadNode{int next,to;}road[MAXN<<];
int tot=,first[MAXN];
struct EdgeNode{int next,to;}edge[MAXN<<];
int cnt=,head[MAXN<<];
inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
multiset<int>::iterator ist;
struct BlockNode
{
multiset<int>st; int val;
inline void insert(int x) {st.insert(x); val=*st.begin();}
inline void change(int x,int y) {st.erase(*st.find(x)); st.insert(y); val=*st.begin();}
}B[MAXN<<];
namespace Graph
{
inline void AddRoad(int u,int v) {tot++; road[tot].next=first[u]; first[u]=tot; road[tot].to=v;}
inline void InsertRoad(int u,int v) {AddRoad(u,v); AddRoad(v,u);}
int dfn[MAXN],low[MAXN],dfsn,bcc,now,belong[MAXN],size[MAXN],cut[MAXN],st[MAXN],top;
inline void Tarjan(int now)
{
dfn[now]=low[now]=++dfsn; st[++top]=now;
for (int i=first[now]; i; i=road[i].next)
if (!dfn[road[i].to])
{
Tarjan(road[i].to); low[now]=min(low[now],low[road[i].to]);
if (dfn[now]<=low[road[i].to])
{
bcc++; cut[now]=; int tp=;
while ()
{
tp=st[top--]; belong[tp]=bcc;
if (cut[tp]) InsertEdge(tp+N,bcc); if (tp==road[i].to) break;
}
InsertEdge(now+N,bcc);
}
}
else low[now]=min(low[now],dfn[road[i].to]);
}
inline void reBuild()
{
for (int i=; i<=N; i++) if (!dfn[i]) Tarjan(i);
for (int i=; i<=N; i++)
{
if (i!=) B[belong[i]].insert(val[i]);
if (cut[i]) B[i+N].insert(INF);
}
}
}
namespace SegmentTree
{
struct SegmentTreeNode{int l,r,minx;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Update(int now) {tree[now].minx=min(tree[ls].minx,tree[rs].minx);}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r;
if (l==r) {tree[now].minx=Val[l]; return;}
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void Change(int now,int pos,int D)
{
int l=tree[now].l,r=tree[now].r;
if (l==r) {tree[now].minx=D; return;}
int mid=(l+r)>>;
if (pos<=mid) Change(ls,pos,D);
if (pos>mid) Change(rs,pos,D);
Update(now);
}
inline int Query(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) return tree[now].minx;
int mid=(l+r)>>,re=INF;
if (L<=mid) re=min(re,Query(ls,L,R));
if (R>mid) re=min(re,Query(rs,L,R));
return re;
}
}
namespace TreePartition
{
int fa[MAXN<<],size[MAXN<<],son[MAXN<<],deep[MAXN<<],pl[MAXN<<],dfn,pre[MAXN<<],top[MAXN<<];
inline void DFS_1(int now)
{
size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now])
{
fa[edge[i].to]=now;
deep[edge[i].to]=deep[now]+;
DFS_1(edge[i].to);
size[now]+=size[edge[i].to];
if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
}
}
inline void DFS_2(int now,int chain)
{
pl[now]=++dfn; pre[dfn]=now; top[now]=chain; Val[dfn]=B[now].val;
if (son[now]) DFS_2(son[now],chain);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now] && edge[i].to!=son[now])
DFS_2(edge[i].to,edge[i].to);
}
inline int LCA(int u,int v)
{
while (top[u]!=top[v])
{
if (deep[top[u]]<deep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if (deep[u]>deep[v]) swap(u,v);
return u;
}
inline int Query(int x,int y)
{
x=Graph::cut[x]? x+N:Graph::belong[x]; y=Graph::cut[y]? y+N:Graph::belong[y];
int re=INF; int lca=LCA(x,y);
if (lca<=Graph::bcc) lca=fa[lca]; re=val[lca-N];
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
re=min(re,SegmentTree::Query(,pl[top[x]],pl[x]));
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
re=min(re,SegmentTree::Query(,pl[x],pl[y]));
return re;
}
inline void Change(int pos,int D) {SegmentTree::Change(,pl[pos],D);}
}
int main()
{
N=read(),M=read(),Q=read();
for (int i=; i<=N; i++) val[i]=read();
for (int x,y,i=; i<=M; i++) x=read(),y=read(),Graph::InsertRoad(x,y);
Graph::reBuild();
// for (int i=1; i<=N; i++) printf("%d %d %d %d\n",dfn[i],low[i],cut[i],belong[i]);
TreePartition::DFS_1(N+); TreePartition::DFS_2(N+,N+);
SegmentTree::BuildTree(,,TreePartition::dfn);
while (Q--)
{
char opt[]; scanf("%s",opt); int x=read(),y=read();
switch (opt[])
{
case 'C': if (x!=) {B[Graph::belong[x]].change(val[x],y); TreePartition::Change(Graph::belong[x],B[Graph::belong[x]].val);} val[x]=y; break;
case 'A': if (x==y) printf("%d\n",val[x]); else printf("%d\n",TreePartition::Query(x,y)); break;
}
}
return ;
}

UOJ上跑的还挺快QAQ...就是死活压不到6000ms+....

【Codefoces487E/UOJ#30】Tourists Tarjan 点双连通分量 + 树链剖分的更多相关文章

  1. CF487 E. Tourists [点双连通分量 树链剖分 割点]

    E. Tourists 题意: 无向连通图 C a w: 表示 a 城市的纪念品售价变成 w. A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值 ...

  2. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  3. BZOJ 4732 UOJ #268 [清华集训2016]数据交互 (树链剖分、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4732 (UOJ) http://uoj.ac/problem/268 题解 ...

  4. 2018.10.30 NOIP训练 【模板】树链剖分(换根树剖)

    传送门 纯粹是为了熟悉板子. 然后发现自己手生了足足写了差不多25min而且输出的时候因为没开long longWA了三次还不知所云 代码

  5. uoj 30 tourists

    题目大意: 一个无向图 每个点有权值 支持两个操作 1 修改某个点的权值 2 查询a-b所有简单路径的点上的最小值 思路: 可以把图变成圆方树 然后树链剖分 维护 对于每个方点使用可删堆维护 #inc ...

  6. BZOJ_4326_[NOIP2015]_运输计划_(二分+LCA_树链剖分/Tarjan+差分)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=4326 给出一棵带有边权的树,以及一系列任务,任务是从树上的u点走到v点,代价为u到v路径上的权 ...

  7. JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分

    http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...

  8. CF487E Tourists(圆方树+树链剖分+multiset/可删堆)

    CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...

  9. UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...

随机推荐

  1. Ajax.BeginForm参数详解

    在Asp.Net的MVC中的语法,在Razor页面中使用,替代JQuery的Ajax使用,方便快捷. 使用Ajax.BeginForm方法会生成一个form表单,最后以Ajax的方式提交表单数据:需要 ...

  2. Linux下开启关闭SeLinux

    SELinux (Security-Enhanced Linux) in Fedora is an implementation of mandatory access control in the ...

  3. Symantec Backup Exec 2010 Agent For Linux安装

    以前写过一篇文章介绍过Symantec Backup Exec 2012 Agent For Linux安装安装,今天介绍一下Symantec Backup Exec 2010 Agent For L ...

  4. sublime3 集成angularJs插件

    sublime是web开发中一款轻量级高效编辑器,十分适合前端开发(安装sublime是需要注册的,请支持正版) 1.安装sublime3(http://www.sublimetext.com/3) ...

  5. 记录sql语句的执行记录,用于分析

    SET STATISTICS PROFILE ONSET STATISTICS IO ONSET STATISTICS TIME ONGO --这之间是要执行的脚本select * from [Use ...

  6. 常用python机器学习库总结

    开始学习Python,之后渐渐成为我学习工作中的第一辅助脚本语言,虽然开发语言是Java,但平时的很多文本数据处理任务都交给了Python.这些年来,接触和使用了很多Python工具包,特别是在文本处 ...

  7. ELF Format 笔记(十五)—— 符号哈希表

    ilocker:关注 Android 安全(新手) QQ: 2597294287 符号哈希表用于支援符号表的访问,能够提高符号搜索速度. 下表用于解释该哈希表的组织,但该格式并不属于 ELF 规范. ...

  8. 【原】HTML5 新增的结构元素——能用并不代表对了

    做移动端有一段时间,今天有同事问了我 article 和 section 标签的使用,模模糊糊的解释了下,他似懂非懂,有点小尴尬.忽然间觉得自己有必要再翻翻书籍,重温下 html5 的新元素.html ...

  9. 第12章 Java字符串

    1.什么是Java中的字符串 字符串String并不是一种数据类型,而是一个类对象,在java.lang包中,只不过在默认情况下java都是自动导入的,所以可以直接使用创建一个String对象的方法有 ...

  10. kettle启动“Error: could not create the Java Virtual Machine”

    因为我的操作系统是32bit,而Ketttle的Spoon脚本中,默认是PENTAHO_DI_JAVA_OPTIONS="-Xms1024m" "-Xmx2048m&qu ...