ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】CF487E Tourists

2021-09-20 20:35:06  阅读:143  来源: 互联网

标签:nodepos int 题解 pos ++ dfn low CF487E Tourists


CF487E Tourists

写完这题已经完全自闭了 调了好久……

题目大意

就是求一张图中两点间所有路径中经过的点的最小值,带修。

解法

我们先考虑一下性质:对于无向图显然不好做,考虑一下咋转化成一棵树。

那就往圆方树考虑呗,本题有啥性质?

观察到:

对于一个点双,必然存在一条路径走过该点双中的最小值。

证明比较简单。由于点双内两点之间没有一个必经点,所以我们必定可以留出一个点从走过的那个最小值点再走出去。

那么就考虑建立圆方树叭。码套路,先上一个 tarjan 找点双……

细节1 注意点双的形成是需要满足 low[j]>=dfn[x] 的,不要犯傻打错了。

好的,接下来怎么修改?考虑回答询问的同时其实也就能想到怎么维护修改:扔一个树剖就好了。

那就考虑写树剖叭。码套路,先上两个 dfs ……

细节2 注意树剖的 query 啥的别打错了……

好嘞,上述准备工作都做好了,写个修改测样例……挂掉了。

冷静分析:发现不论改方点还是圆点,都会影响到周围的点。

怎么办,暴力修改?那显然不切实际,一个菊花图就可以卡爆你。

继续考虑如何高效维护。我们知道,一个方点代表一个点双,那么,对于圆方树的树结构,每一个方点的答案其实除了它的孩子还要包含其父亲。这点也就恰好让维护变得不方便起来。

那么我们不妨先考虑无视掉父亲的影响,只维护孩子,怎么做?

维护一个 multiset 对每个方点,每次直接拿这个来暴力更新方点权值。

好的,现在这里可以实现了,那带上父亲呢?

冷静分析一波,这个父亲的影响需要满足两个条件:

  • 这个点是方点

  • 这个点的父亲没有被计算到

那同时满足下列两个条件的点就只有可能是……

最近公共祖先 \((LCA)\)

所以对于每一组询问实际只有一个点需要被特殊对待!

那么就直接做就好了。

最后再附赠细节3:

更新 low[x] 不要拿 low[j] 啊……(在不 dfs 的时候),调了好久……

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=200100;
int head[N],tot,Head[N],tto,n,m,q,w[N];
struct E {
	int nxt,to;
} e[N<<1],edge[N<<1];
inline int read(){
	int s=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)){
		s=s*10-'0'+ch;
		ch=getchar();
	} 
	return s;
}
int nodepos,ddf,rk[N],cir[N],To[N];
inline int Min(int x,int y) {return x<y?x:y;}
multiset<int> S[N];
inline void link(int x,int y,int w=0) {
	if(w) {
		edge[++tto]=(E) {
			Head[x],y
		};
		Head[x]=tto;
		return;
	}
	e[++tot]=(E) {
		head[x],y
	};
	head[x]=tot;
}
int son[N],siz[N],dfn[N],low[N],st[N],top;
int ttop[N],pa[N],dfstime,vis[N],dep[N];
void dfs1(int x,int fa) {
	siz[x]=1;
	dep[x]=dep[fa]+1;
	pa[x]=fa;
	for(int i=Head[x]; i; i=edge[i].nxt) {
		int j=edge[i].to;
		if(j==fa)continue;
		dfs1(j,x);
		siz[x]+=siz[j];
		if(siz[j]>siz[son[x]])son[x]=j;
	}
}
void dfs2(int x,int t) {
	rk[dfn[x]=++ddf]=x;
	ttop[x]=t;
	if(!son[x])return;
	dfs2(son[x],t);
	for(int i=Head[x]; i; i=edge[i].nxt) {
		int j=edge[i].to;
		if(j==son[x]||j==pa[x])continue;
		dfs2(j,j);
	}
}
void tarjan(int x,int root) {
	dfn[x]=low[x]=++dfstime;
	st[++top]=x;
	if(x==root&&!head[x]) {
		++nodepos;
		To[nodepos]=x;
		cir[x]=nodepos;
		link(x,nodepos,1);
		link(nodepos,x,1);
		return;
	}
	int ch=0;
	for(int i=head[x]; i; i=e[i].nxt) {
		int j=e[i].to;
		if(!dfn[j]) {
			++ch;
			tarjan(j,root);
			low[x]=Min(low[x],low[j]);
			if(dfn[x]<=low[j]&&x!=root)vis[x]=1;
			if(x==root&&ch>1)vis[x]=1;
			if(low[j]>=dfn[x]) {
				int vex=-1;
				++nodepos;
				To[nodepos]=x;
				do {
					vex=st[top--];
					cir[vex]=nodepos;
					link(vex,nodepos,1);
					link(nodepos,vex,1);
				} while(vex!=j);
				cir[x]=nodepos;
				link(nodepos,x,1);
				link(x,nodepos,1);
			}
		} else low[x]=Min(low[x],dfn[j]);
	}
}
namespace SGT {
	int mi[N<<2],ls[N<<2],rs[N<<2],node;
	inline void pushup(int x) {
		mi[x]=Min(mi[ls[x]],mi[rs[x]]);
	}
	void build(int &x,int l,int r) {
		x=++node;
		if(l==r) {
			mi[x]=w[rk[l]];
			return;
		}
		int mid=(l+r)>>1;
		build(ls[x],l,mid);
		build(rs[x],mid+1,r);
		pushup(x);
	}
	void change(int x,int L,int R,int pos,int v) {
		if(L==R) {
			mi[x]=v;
			return;
		}
		int mid=(L+R)>>1;
		if(pos<=mid)change(ls[x],L,mid,pos,v);
		else change(rs[x],mid+1,R,pos,v);
		pushup(x);
	}
	int query(int x,int L,int R,int l,int r) {
		if(L>=l&&R<=r){return mi[x];} 
		int mid=(L+R)>>1,res=(1LL<<60);
		if(l<=mid)res=query(ls[x],L,mid,l,r);
		if(mid<r)res=Min(res,query(rs[x],mid+1,R,l,r));
		return res;
	}
}
using namespace SGT;
int rt;
int Query(int u,int v) {
	int res=(1LL<<60);
	while(ttop[u]!=ttop[v]) {
		if(dep[ttop[u]]<dep[ttop[v]])swap(u,v);
		res=Min(res,query(rt,1,nodepos,dfn[ttop[u]],dfn[u]));
		u=pa[ttop[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	res=Min(res,query(rt,1,nodepos,dfn[v],dfn[u]));
	if(dep[u]>dep[v])swap(u,v);
	if(u>n)res=Min(res,w[pa[u]]);
	return res;
}
void Change(int pos,int v) {
	change(rt,1,nodepos,dfn[pos],v);
	if(pos==1) {
		w[pos]=v;
		return;
	}
	int o=pa[pos];
	S[o-n].erase(S[o-n].find(w[pos]));
	S[o-n].insert(v);
	int minv=*S[o-n].begin();
	if(minv==w[o]){
		w[pos]=v;
		return;
	}
	change(rt,1,nodepos,dfn[o],minv);
	w[o]=minv;
	w[pos]=v;
}
inline void write(int x){
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
signed main() {
	freopen("in.txt","r",stdin);
	n=read();m=read();q=read();
	for(int i=1; i<=n; ++i)w[i]=read();
	for(int i=1; i<=m; ++i) {
		int u=read(),v=read();
		link(u,v);
		link(v,u);
	}
	nodepos=n;
	tarjan(1,1);
	memset(dfn,0,sizeof dfn);
	dfs1(1,0);
	dfs2(1,1);
	for(int i=2; i<=n; ++i) {
		S[pa[i]-n].insert(w[i]);
	}
	for(int i=n+1; i<=nodepos; ++i)
		w[i]=(S[i-n].empty()?(1LL<<60):(*S[i-n].begin()));
	memset(mi,0x7f,sizeof mi);
	build(rt,1,nodepos);
	while(q--) {
		int u,v;
		char opt;
		cin>>opt;
		u=read();v=read();
		if(opt=='A') {
			write(Query(u,v));
			putchar('\n');
			continue;
		}
		Change(u,v);
	}
	return 0;
}

标签:nodepos,int,题解,pos,++,dfn,low,CF487E,Tourists
来源: https://www.cnblogs.com/h-lka/p/15315107.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有