[UOJ30]/[CF487E]Tourists

[UOJ30]/[CF487E]Tourists

题目大意:

一个\(n(n\le10^5)\)个点\(m(m\le10^5)\)条边的无向图,每个点有点权。\(q(q\le10^5)\)次操作,操作包含以下两种:

  1. 修改一个点的点权。
  2. 找到一条连接\((u,v)\)的简单路径,使得最小权值最小。求最小权值。

思路:

缩点后建圆方树,用树链剖分维护权值。发现修改圆点后可能修改\(O(n)\)个方点。

考虑更改方点的含义,让方点只维护子结点,因此修改一个圆点只需要修改它的父亲方点(利用BFS序+线段树)。

统计信息时若\(\operatorname{lca}(u,v)\)为方点,则额外处理一下\(par[\operatorname{lca}(u,v)]\)的值。

时间复杂度\(\mathcal O(n\log^2n)\)

源代码:

#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
inline char getalpha() {
	register char ch;
	while(!isalpha(ch=getchar()));
	return ch;
}
const int N=2e5+1;
int n,m,q,cnt;
struct Edge {
	int x,y;
};
Edge edge[N];
int w[N];
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
	e[u].push_back(v);
	e[v].push_back(u);
}
std::stack<int> s;
int dfn[N],low[N],par[N];
void tarjan(const int &x,const int &par) {
	s.push(x);
	dfn[x]=low[x]=++dfn[0];
	for(auto &y:e[x]) {
		if(y==par) continue;
		if(!dfn[y]) {
			tarjan(y,x);
			low[x]=std::min(low[x],low[y]);
			if(low[y]>=dfn[x]) {
				cnt++;
				for(register int z=0;z!=y;s.pop()) {
					z=s.top();
					edge[m++]=(Edge){cnt,z};
				}
				edge[m++]=(Edge){cnt,x};
			}
		} else low[x]=std::min(low[x],dfn[y]);
	}
}
int dep[N],top[N],son[N],size[N];
void dfs(const int &x,const int &par) {
	::par[x]=par;
	dep[x]=dep[par]+1;
	size[x]=1;
	for(unsigned i=0;i<e[x].size();i++) {
		const int &y=e[x][i];
		if(y==par) continue;
		dfs(y,x);
		size[x]+=size[y];
		if(size[y]>size[son[x]]) son[x]=y;
	}
}
void dfs(const int &x) {
	dfn[x]=++dfn[0];
	top[x]=x==son[par[x]]?top[par[x]]:x;
	if(son[x]) dfs(son[x]);
	for(unsigned i=0;i<e[x].size();i++) {
		const int &y=e[x][i];
		if(y==par[x]||y==son[x]) continue;
		dfs(y);
	}
}
int bfn[N],beg[N];
inline void bfs() {
	static bool vis[N];
	static std::queue<int> q;
	q.push(1);
	while(!q.empty()) {
		const int &x=q.front();
		vis[x]=true;
		bfn[x]=++bfn[0];
		if(!beg[par[x]]) beg[par[x]]=bfn[x];
		size[x]=0;
		if(x>n) w[x]=INT_MAX;
		for(register auto &y:e[x]) {
			if(vis[y]) continue;
			q.push(y);
			size[x]++;
			if(x>n) w[x]=std::min(w[x],w[y]);
		}
		q.pop();
	}
}
class SegmentTree {
	#define _left <<1
	#define _right <<1|1
	#define mid ((b+e)>>1)
	private:
		int val[N<<2];
		void push_up(const int &p) {
			val[p]=std::min(val[p _left],val[p _right]);
		}
	public:
		void modify(const int &p,const int &b,const int &e,const int &x,const int &y) {
			if(b==e) {
				val[p]=y;
				return;
			}
			if(x<=mid) modify(p _left,b,mid,x,y);
			if(x>mid) modify(p _right,mid+1,e,x,y);
			push_up(p);
		}
		int query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
			if(b==l&&e==r) return val[p];
			int ret=INT_MAX;
			if(l<=mid) ret=std::min(ret,query(p _left,b,mid,l,std::min(mid,r)));
			if(r>mid) ret=std::min(ret,query(p _right,mid+1,e,std::max(mid+1,l),r));
			return ret;
		}
	#undef _left
	#undef _right
	#undef mid
};
SegmentTree t1,t2;
inline int query(int x,int y) {
	int ret=INT_MAX;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
		ret=std::min(ret,t1.query(1,1,cnt,dfn[top[x]],dfn[x]));
		x=par[top[x]];
	}
	if(dep[x]<dep[y]) std::swap(x,y);
	ret=std::min(ret,t1.query(1,1,cnt,dfn[y],dfn[x]));
	if(y>n) ret=std::min(ret,t1.query(1,1,cnt,dfn[par[y]],dfn[par[y]]));
	return ret;
}
int main() {
	n=cnt=getint(),m=getint(),q=getint();
	for(register int i=1;i<=n;i++) w[i]=getint();
	for(register int i=0;i<m;i++) {
		add_edge(getint(),getint());
	}
	m=0;
	for(register int i=1;i<=n;i++) {
		if(!dfn[i]) tarjan(i,0);
	}
	for(register int i=1;i<=n;i++) e[i].clear();
	for(register int i=0;i<m;i++) {
		const int &u=edge[i].x,&v=edge[i].y;
		add_edge(u,v);
	}
	dfn[0]=0;
	dfs(1,0);
	dfs(1);
	bfs();
	for(register int i=1;i<=cnt;i++) t1.modify(1,1,cnt,dfn[i],w[i]);
	for(register int i=1;i<=cnt;i++) t2.modify(1,1,cnt,bfn[i],w[i]);
	for(register int i=0;i<q;i++) {
		const char opt=getalpha();
		const int x=getint(),y=getint();
		if(opt=='C') {
			t1.modify(1,1,cnt,dfn[x],y);
			if(par[x]<=n) continue;
			t2.modify(1,1,cnt,bfn[x],y);
			const int tmp=t2.query(1,1,cnt,beg[par[x]],beg[par[x]]+size[par[x]]-1);
			t1.modify(1,1,cnt,dfn[par[x]],tmp);
		}
		if(opt=='A') {
			printf("%d\n",query(x,y));
		}
	}
	return 0;
}
posted @ 2018-08-09 16:08  skylee03  阅读(165)  评论(0编辑  收藏  举报