zoukankan      html  css  js  c++  java
  • [UOJ30]/[CF487E]Tourists

    [UOJ30]/[CF487E]Tourists

    题目大意:

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

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

    思路:

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

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

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

    时间复杂度(mathcal O(nlog^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
    ",query(x,y));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    REPL
    java实现指数问题
    java实现指数问题
    java实现串逐位和(C++)
    java实现串逐位和(C++)
    java实现串逐位和(C++)
    java实现串逐位和(C++)
    java实现串逐位和(C++)
    手工日期计算法
    手工日期计算法
  • 原文地址:https://www.cnblogs.com/skylee03/p/9449603.html
Copyright © 2011-2022 走看看