首页 > 学院 > 开发设计 > 正文

codeforces E. Tourists (树链剖分+tarjan)

2019-11-06 07:30:22
字体:
来源:转载
供稿:网友

E. Touriststime limit per test2 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard 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.

Examplesinput
3 3 31231 22 31 3A 2 3C 1 5A 2 3output
12input
7 9 412345671 22 51 52 33 42 45 66 75 7A 2 3A 6 4A 6 7A 3 3output
2153Note

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].

题目大意:给出一个无向简单图,保证任意顶点之间是连通的。每个点有一个点权。

操作分为两种,一种是更改点的点权;另一种是给出起点和终点,求从起点到终点的路径中可能经过的最小点权。

题解:树链剖分+tarjan

给出点双连通分量的定义:对于一个连通图,如果任意两点至少存在两条点不重复路径,则称这个图为点双连通的(简称双连通)。那么同属一个点双连通分量的点,到达其中的一个点就一定能到达连通分量中的所有点。但是我们无法直接进行缩点,因为有些割点会属于很多的点双连通图分量。所以我们对于每个点双连通分量新建一个节点,将所有属于他的点都与他连边,然后我们会得到一颗树。这颗树有不错的性质,首先一定是原图的点与新建节点交替分布的(即不会存在两个原图的点直接相连)。所有非叶子节点的原图的点对应的都是原图的割点。这样我们就得到了一棵树,是所有的点都与他所属的点双相连,并且没有冲突。

那么我们就可以在这棵树上搞事情了。

对于点双的权值,我们定义为他所有儿子节点中的最小点权,这个需要用multiset来维护。

修改一个点的点权也需要对应的修改,他所属的点双(父节点)。

对于查询,因为我们只要经过点双中的一个点就可以获取点双中的最小权值。所以我们对树进行树链剖分,然后查询路径上的最小值即可。需要注意的是如果两个点的lca是新建的点双节点那么我们还要加入fa[lca]的权值,fa[lca]也是属于lca这点双的,只不过是我们没有维护进去。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<set>#define N 500003#define inf 1000000000using namespace std;int n,m,q,tot,cnt,sz,top,root,n1;int belong[N],st[N],low[N],dfsn[N],bl[N],head[N],nxt[N],next[N],point[N],val[N];int u[N],v[N],ins[N],vis[N],mark[N],tr[N*4],pos[N],p[N],fa[N],deep[N],size[N],son[N];int bk[N];multiset<int> c[N];void add(int x,int y){	tot++; next[tot]=head[x]; head[x]=tot; u[tot]=y;	tot++; next[tot]=head[y]; head[y]=tot; u[tot]=x;}void addedge(int x,int y){	tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;	tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void tarjan(int x){	st[++top]=x; low[x]=dfsn[x]=++sz; ins[x]=1;	for (int i=head[x];i;i=next[i]) {		int j=u[i];		if (!dfsn[j]) {			tarjan(j);			low[x]=min(low[x],low[j]);			if (dfsn[x]<=low[j]) {				++cnt; mark[x]=1; int k;				while (1){					k=st[top--];					bl[k]=cnt;					addedge(cnt+n,k);					if (k==j) break;				}				addedge(cnt+n,x);				root=x; 			}		}		else if (ins[j]) low[x]=min(low[x],dfsn[j]);	}}void search(int x){	addedge(cnt+n,x); vis[x]=cnt; bl[x]=cnt;	for (int i=head[x];i;i=next[i]) {		if (mark[u[i]]&&vis[u[i]]!=cnt) {			vis[u[i]]=cnt; addedge(cnt+n,u[i]);			continue;		}		if (vis[u[i]]) continue;		search(u[i]);	}}void dfs(int x,int f){	fa[x]=f; size[x]=1; deep[x]=deep[f]+1;	for (int i=point[x];i;i=nxt[i]) {		if (v[i]==f) continue;		dfs(v[i],x);		size[x]+=size[v[i]];		if (size[son[x]]<size[v[i]]) son[x]=v[i];	}}void dfs1(int x,int chain){	belong[x]=chain; pos[x]=++sz; p[sz]=x;	if (!son[x]) return;	dfs1(son[x],chain);	for (int i=point[x];i;i=nxt[i])	 if (v[i]!=fa[x]&&v[i]!=son[x])	  dfs1(v[i],v[i]);}void update(int now){	tr[now]=min(tr[now<<1],tr[now<<1|1]);}void build(int now,int l,int r){	if (l==r) {		tr[now]=val[p[l]];		return;	}	int mid=(l+r)/2;	build(now<<1,l,mid);	build(now<<1|1,mid+1,r);	update(now);}void pointchange(int now,int l,int r,int x,int v){	if (l==r) {		tr[now]=v;		return;	}	int mid=(l+r)/2;	if (x<=mid) pointchange(now<<1,l,mid,x,v);	else pointchange(now<<1|1,mid+1,r,x,v);	update(now);}int find(int now,int l,int r,int ll,int rr){	if (ll<=l&&r<=rr) return tr[now];	int mid=(l+r)/2; int ans=inf;	if (ll<=mid) ans=min(ans,find(now<<1,l,mid,ll,rr));	if (rr>mid) ans=min(ans,find(now<<1|1,mid+1,r,ll,rr));	return ans;}int solve(int x,int y){	int ans=inf;	while (belong[x]!=belong[y]) {		if (deep[belong[x]]<deep[belong[y]]) swap(x,y);		ans=min(ans,find(1,1,n,pos[belong[x]],pos[x]));		x=fa[belong[x]];	}	if (deep[x]>deep[y]) swap(x,y);	ans=min(ans,find(1,1,n,pos[x],pos[y]));	if (x>n1&&fa[x]) ans=min(ans,find(1,1,n,pos[fa[x]],pos[fa[x]]));	return ans;}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;i<=m;i++) {		int x,y; scanf("%d%d",&x,&y);		add(x,y);	}	for (int i=1;i<=2*n;i++) bk[i]=i;	tot=0;	for (int i=1;i<=n;i++)	 if (!dfsn[i]) tarjan(i);	if (cnt==1) root=cnt+n;	dfs(root,0);	sz=0; dfs1(root,root);	for (int i=n+1;i<=n+cnt;i++) val[i]=inf;	for (int i=1;i<=n;i++) {		if (i==root) continue;	    bl[i]=fa[i]; int t=bl[i];		c[t].insert(val[i]);		val[t]=min(val[t],*c[t].begin());	}	n1=n; n+=cnt; 	build(1,1,n);	for (int i=1;i<=q;i++) {		char opt[10]; int x,y; scanf("%s%d%d",opt,&x,&y);		if (opt[0]=='A') {			printf("%d/n",solve(x,y));		}		else {			pointchange(1,1,n,pos[x],y); 			if (x==root) {				val[x]=y;				continue;			}			int t=bl[x];			c[t].erase(c[t].find(val[x])); val[x]=y;			c[t].insert(val[x]); 			val[t]=*c[t].begin();			pointchange(1,1,n,pos[t],val[t]);		}	}}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表