zoukankan      html  css  js  c++  java
  • UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html

    题目传送门 - UOJ#30

    题意

      uoj写的很简洁、清晰,这里就不抄一遍了。

    题解

      首先建出圆方树。接下来,我们称"圆点"为原来有的点,"方点"为新增的点。

      然后先只考虑在线询问如何做。

        ——把方点的值设置成所有与他连边的圆点的权值的最小值,直接在圆方树上树链剖分再套个线段树支持一下区间询问即可。

      然后会发现这样做支持不了修改操作。

        ——直接来个菊花图不断修改根节点就GG了。

      于是我们考虑进一步想办法。

      我们把方点的值重新定义成“在圆方树上,该点的儿子的权值的最小值”。那么,在询问的时候,其他都一样,但是如果 lca 为方点,那么加上其 fa 对 min 的贡献即可。

      时间复杂度 $O(nlog ^2 n )$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL read(){
    	LL x=0,f=1;
    	char ch=getchar();
    	while (!isdigit(ch)&&ch!='-')
    		ch=getchar();
    	if (ch=='-')
    		f=-1,ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return x*f;
    }
    const int N=200005,INF=1.1e9;
    int pr[N],dfn[N],low[N],st[N],Time,top,tot;
    multiset <int> Mins[N];
    vector <int> G[N],g[N];
    void Tarjan(int x){
    	low[x]=dfn[x]=++Time,st[++top]=x;
    	for (auto y : G[x])
    		if (!dfn[y]){
    			Tarjan(y);
    			low[x]=min(low[x],low[y]);
    			if (low[y]>=dfn[x]){
    				tot++;
    				g[x].push_back(tot);
    				g[tot].push_back(x);
    				int z;
    				do {
    					z=st[top--];
    					g[z].push_back(tot);
    					g[tot].push_back(z);
    				} while (z!=y);
    			}
    		}
    		else
    			low[x]=min(low[x],dfn[y]);
    }
    namespace sp{
    	int n,outn;
    	int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],cnp=0,val[N];
    	void dfs(int x,int pre,int d){
    		size[x]=1,fa[x]=pre,son[x]=-1,depth[x]=d;
    		for (auto y : g[x])
    			if (y!=pre){
    				dfs(y,x,d+1);
    				size[x]+=size[y];
    				if (son[x]==-1||size[y]>size[son[x]])
    					son[x]=y;
    			}
    	}
    	void Get_Top(int x,int tp){
    		top[x]=tp;
    		ap[p[x]=++cnp]=x;
    		if (son[x]==-1)
    			return;
    		Get_Top(son[x],tp);
    		for (auto y : g[x])
    			if (y!=fa[x]&&y!=son[x])
    				Get_Top(y,y);
    	}
    	int Min[N<<2];
    	void build(int rt,int L,int R){
    		if (L==R)
    			return (void)(Min[rt]=val[ap[L]]);
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		build(ls,L,mid);
    		build(rs,mid+1,R);
    		Min[rt]=min(Min[ls],Min[rs]);
    	}
    	int query(int rt,int L,int R,int xL,int xR){
    		if (xL>xR||L>xR||R<xL)
    			return INF;
    		if (xL<=L&&R<=xR)
    			return Min[rt];
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		return min(query(ls,L,mid,xL,xR),query(rs,mid+1,R,xL,xR));
    	}
    	void update(int rt,int L,int R,int x,int d){
    		if (L==R)
    			return (void)(Min[rt]=d);
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		if (x<=mid)
    			update(ls,L,mid,x,d);
    		else
    			update(rs,mid+1,R,x,d);
    		Min[rt]=min(Min[ls],Min[rs]);
    	}
    	int query(int a,int b){
    		int f1=top[a],f2=top[b],ans=INF;
    		while (f1!=f2){
    			if (depth[f1]<depth[f2])
    				swap(f1,f2),swap(a,b);
    			ans=min(ans,query(1,1,n,p[f1],p[a]));
    			a=fa[f1],f1=top[a];
    		}
    		if (depth[a]>depth[b])
    			swap(a,b);
    		if (a>outn&&fa[a]!=0)
    			ans=min(ans,query(1,1,n,p[fa[a]],p[fa[a]]));
    		return min(ans,query(1,1,n,p[a],p[b]));
    	}
    }
    int main(){
    	int n=tot=read(),m=read(),q=read();
    	for (int i=1;i<=n;i++)
    		pr[i]=read();
    	for (int i=1;i<=m;i++){
    		int a=read(),b=read();
    		G[a].push_back(b);
    		G[b].push_back(a);
    	}
    	Tarjan(1);
    	sp :: dfs(1,0,0);
    	sp :: Get_Top(1,1);
    	for (int i=n+1;i<=tot;i++)
    		Mins[i].insert(INF);
    	for (int i=1;i<=n;i++)
    		Mins[sp :: fa[i]].insert(pr[i]);
    	for (int i=1;i<=n;i++)
    		sp :: val[i]=pr[i];
    	for (int i=n+1;i<=tot;i++)
    		sp :: val[i]=*Mins[i].begin();
    	sp :: build(1,1,sp :: n=tot);
    	sp :: outn=n;
    	while (q--){
    		char s[10];
    		scanf("%s",s);
    		int x=read(),y=read();
    		if (s[0]=='A')
    			printf("%d
    ",sp :: query(x,y));
    		else {
    			int f=sp :: fa[x];
    			if (f){
    				Mins[f].erase(Mins[f].find(pr[x]));
    				Mins[f].insert(pr[x]=y);
    				sp :: update(1,1,sp :: n,sp :: p[f],*Mins[f].begin());
    			}
    			sp :: update(1,1,sp :: n,sp :: p[x],y);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    处理不同方向的文本1.0
    CSS盒模型
    费德曼学习法
    [转]Photoshop中的高斯模糊、高反差保留和Halcon中的rft频域分析研究
    [转]仿射变换及其变换矩阵的理解
    [转]Scintilla开源库使用指南(一
    [转]Scintilla开源库使用指南(二
    [转]C#中WinForm窗体事件的执行次序
    [转]透过IL看C#:switch语句(转)
    [转]程序员必读书单(转)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ30.html
Copyright © 2011-2022 走看看