CF487E Tourists(圆方树+堆+链剖)

本题解并不提供圆方树讲解。
所以不会圆方树的出门右转问yyb
没有修改的话圆方树+链剖。
方点的权值为点双连通分量里的最小值。
然后修改的话圆点照修,每一个方点维护一个小根堆。
考虑到可能被菊花卡死。
我们每一个方点只维护儿子的最小值。
当询问的路径\(lca\)为方点时,\(ans=min(ans,w[fa[lca]])\)即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define ls now<<1
#define rs now<<1|1
const int N=444444;
struct queue{
	priority_queue<int,vector<int>,greater<int> >q1;
	priority_queue<int,vector<int>,greater<int> >q2;
	void push(int x){q1.push(x);}
	void del(int x){q2.push(x);}
	int top(){
		while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();
		return q1.top();
	}
}q[N];
struct Graph{
	int cnt,head[N];
	struct edge{
		int to,nxt;
	}e[N*2];
	void add_edge(int u,int v){
		cnt++;
		e[cnt].nxt=head[u];
		e[cnt].to=v;
		head[u]=cnt;
	}
}g1,g2;
int dfn[N],low[N],tim,stack[N],Top,num;
void Tarjan(int u){
	dfn[u]=low[u]=++tim;
	stack[++Top]=u;
	for(int i=g1.head[u];i;i=g1.e[i].nxt){
		int v=g1.e[i].to;
		if(dfn[v]==0){
			Tarjan(v);
			low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u]){
				g2.add_edge(++num,u);
				g2.add_edge(u,num);
				int x;
				do{
					x=stack[Top--];
					g2.add_edge(num,x);
					g2.add_edge(x,num);
				}while(x!=v);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}
int fa[N],size[N],dep[N],son[N];
int n,w[N];
void dfs1(int u,int f){
	fa[u]=f;
	size[u]=1;
	dep[u]=dep[f]+1;
	for(int i=g2.head[u];i;i=g2.e[i].nxt){
		int v=g2.e[i].to;
		if(v==f)continue;
		if(u>n)q[u].push(w[v]);
		dfs1(v,u);
		size[u]+=size[v];
		if(size[son[u]]<=size[v])son[u]=v;
	}
}
int top[N],id[N],tot;
void dfs2(int u,int tp){
	dfn[u]=++tot;
	top[u]=tp;
	id[tot]=u;
	if(son[u])dfs2(son[u],tp);
	for(int i=g2.head[u];i;i=g2.e[i].nxt){
		int v=g2.e[i].to;
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}
int mn[N*4];
void update(int now){
	mn[now]=min(mn[ls],mn[rs]);
}
void build(int l,int r,int now){
	if(l==r){
		if(id[l]<=n)mn[now]=w[id[l]];
		else mn[now]=q[id[l]].top();
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,ls);
	build(mid+1,r,rs);
	update(now);
}
void change(int l,int r,int x,int c,int now){
	if(l==r){
		mn[now]=c;
		return;
	}
	int mid=(l+r)>>1;
	if(x>mid)change(mid+1,r,x,c,rs);
	else change(l,mid,x,c,ls);
	update(now);
}
int check(int l,int r,int L,int R,int now){
	if(l==L&&r==R)return mn[now];
	int mid=(l+r)>>1;
	if(L>mid)return check(mid+1,r,L,R,rs);
	else if(R<=mid)return check(l,mid,L,R,ls);
	else return min(check(l,mid,L,mid,ls),check(mid+1,r,mid+1,R,rs));
}
int getlca(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])return x;
	else return y;
}
int checkroad(int x,int y){
	int mn=-1;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		if(mn==-1)mn=check(1,num,dfn[top[x]],dfn[x],1);
		else mn=min(mn,check(1,num,dfn[top[x]],dfn[x],1));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	if(mn==-1)mn=check(1,num,dfn[x],dfn[y],1);
	else mn=min(mn,check(1,num,dfn[x],dfn[y],1));
	return mn;
}
int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return sum*f;
}
int Q,m;
int main(){
	n=read();m=read();Q=read();
	num=n;
	for(int i=1;i<=n;i++)w[i]=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		g1.add_edge(u,v);g1.add_edge(v,u);
	}
	Tarjan(1);
	dfs1(1,0);
	dfs2(1,1);
	build(1,num,1);
	char s[3];
	while(Q--){
		scanf("%s",s+1);
		if(s[1]=='C'){
			int x=read(),c=read();
			if(dfn[x]!=1){
				q[fa[x]].del(w[x]);
				q[fa[x]].push(c);
				change(1,num,dfn[fa[x]],q[fa[x]].top(),1);
			}
			w[x]=c;
			change(1,num,dfn[x],c,1);
		}
		else{
			int x=read(),y=read();
			int lca=getlca(x,y);
			int tmp=checkroad(x,y);
			printf("%d\n",lca<=n?tmp:min(tmp,w[fa[lca]]));
		}
	}
	return 0;
}
posted @ 2019-03-07 22:04  Xu-daxia  阅读(210)  评论(0编辑  收藏  举报