zoukankan      html  css  js  c++  java
  • CF487E Tourists【圆方树+tarjan+multiset+树剖+线段树】

    圆方树不仅能解决仙人掌问题(虽然我仙人掌问题也没用过圆方树都是瞎搞过去的),还可以解决一般图的问题
    一般图问题在于缩完环不是一棵树,所以就缩点双(包括双向边)
    每个方点存他所在点双内除根以外的点的最小权值,这样的好处是更新原点的时候不用更新它一圈的方点,只更新父亲即可
    树剖维护,然后查的时候如果lca是方点,就额外查一下他的父亲

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<set>
    using namespace std;
    const int N=200005;
    int n,nn,m,q,a[N],va[N],h[N],cnt,bl[N],dfn[N],low[N],tot,s[N],top,si[N],fa[N],de[N],hs[N],fr[N],id[N],rl[N];
    char o[5];
    vector<pair<int,int> >b;
    multiset<int>st[N];
    struct qwe
    {
    	int ne,to;
    }e[N<<1];
    struct xds
    {
    	int l,r,mn;
    }t[N<<2];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void add(int u,int v)
    {//cerr<<u<<" "<<v<<endl;
    	cnt++;
    	e[cnt].ne=h[u];
    	e[cnt].to=v;
    	h[u]=cnt;
    }
    void tarjan(int u)
    {
    	dfn[u]=low[u]=++tot;
    	s[++top]=u;
    	for(int i=h[u];i;i=e[i].ne)
    	{
    		if(!dfn[e[i].to])
    		{
    			tarjan(e[i].to);
    			low[u]=min(low[u],low[e[i].to]);
    			if(low[e[i].to]>=dfn[u])
    			{
    				b.push_back(make_pair(++n,u));
    				a[n]=1e9;
    				while(s[top]!=e[i].to)
    				{
    					a[n]=min(a[n],a[s[top]]);
    					bl[s[top]]=n;
    					st[n].insert(a[s[top]]);
    					b.push_back(make_pair(n,s[top--]));
    				}
    				a[n]=min(a[n],a[s[top]]);
    				bl[s[top]]=n;
    				st[n].insert(a[s[top]]);
    				b.push_back(make_pair(n,s[top--]));
    			}
    		}
    		else
    			low[u]=min(low[u],dfn[e[i].to]);
    	}
    }
    void dfs1(int u,int fat)
    {
    	fa[u]=fat;
    	de[u]=de[fat]+1;
    	si[u]=1;
    	for(int i=h[u];i;i=e[i].ne)
    		if(e[i].to!=fat)
    		{
    			dfs1(e[i].to,u);
    			si[u]+=si[e[i].to];
    			if(si[e[i].to]>si[hs[u]])
    				hs[u]=e[i].to;
    		}
    }
    void dfs2(int u,int top)
    {
    	fr[u]=top;
    	id[u]=++tot;
    	rl[tot]=u;
    	if(!hs[u])
    		return;
    	dfs2(hs[u],top);
    	for(int i=h[u];i;i=e[i].ne)
    		if(e[i].to!=fa[u]&&e[i].to!=hs[u])
    			dfs2(e[i].to,e[i].to);
    }
    void build(int ro,int l,int r)
    {
    	t[ro].l=l,t[ro].r=r;
    	if(l==r)
    	{
    		t[ro].mn=a[rl[l]];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(ro<<1,l,mid);
    	build(ro<<1|1,mid+1,r);
    	t[ro].mn=min(t[ro<<1].mn,t[ro<<1|1].mn);
    }
    void update(int ro,int p,int v)
    {
    	if(t[ro].l==t[ro].r)
    	{
    		t[ro].mn=v;
    		return;
    	}
    	int mid=(t[ro].l+t[ro].r)>>1;
    	if(p<=mid)
    		update(ro<<1,p,v);
    	else
    		update(ro<<1|1,p,v);
    	t[ro].mn=min(t[ro<<1].mn,t[ro<<1|1].mn);
    }
    int ques(int ro,int l,int r)
    {
    	if(t[ro].l==l&&t[ro].r==r)
    		return t[ro].mn;
    	int mid=(t[ro].l+t[ro].r)>>1;
    	if(r<=mid)
    		return ques(ro<<1,l,r);
    	else if(l>mid)
    		return ques(ro<<1|1,l,r);
    	else
    		return min(ques(ro<<1,l,mid),ques(ro<<1|1,mid+1,r));
    }
    int wen(int u,int v)
    {
    	int ans=1e9;
    	while(fr[u]!=fr[v])
    	{
    		if(de[fr[u]]<de[fr[v]])
    			swap(u,v);
    		ans=min(ans,ques(1,id[fr[u]],id[u]));
    		u=fa[fr[u]];
    	}
    	if(de[u]>de[v])
    		swap(u,v);
    	ans=min(ans,ques(1,id[u],id[v]));
    	if(u>nn)
    		ans=min(ans,a[fa[u]]);
    	return ans;
    }
    int main()
    {
    	nn=n=read(),m=read(),q=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		add(x,y),add(y,x);
    	}
    	tarjan(1);//cerr<<"OK"<<endl;
    	cnt=0,tot=0;
    	memset(h,0,sizeof(h));
    	for(int i=0,len=b.size();i<len;i++)
    		add(b[i].first,b[i].second),add(b[i].second,b[i].first);
    	dfs1(1,0);
    	dfs2(1,1);
    	build(1,1,n);
    	while(q--)
    	{
    		scanf("%s",o+1);
    		if(o[1]=='C')
    		{
    			int x=read(),v=read();
    			update(1,id[x],v);
    			if(bl[x])
    			{
    				st[bl[x]].erase(st[bl[x]].find(a[x]));
    				a[x]=v;
    				st[bl[x]].insert(a[x]);
    				update(1,id[bl[x]],*st[bl[x]].begin());
    			}
    			else
    				a[x]=v;
    		}
    		else
    		{
    			int x=read(),y=read();
    			printf("%d
    ",wen(x,y));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    从零搭建Spring Boot脚手架(4):手写Mybatis通用Mapper
    从零搭建Spring Boot脚手架(3):集成mybatis
    从零搭建Spring Boot脚手架(2):增加通用的功能
    从零搭建Spring Boot脚手架(1):开篇以及技术选型
    Hibernate Validator校验参数全攻略
    Spring Data R2DBC响应式操作MySQL
    Spring Security 实战干货:从零手写一个验证码登录
    Spring Security 实战干货:图解用户是如何登录的
    基于.NetCore3.1系列 —— 日志记录之日志核心要素揭秘
    基于.NetCore3.1系列 —— 日志记录之日志配置揭秘
  • 原文地址:https://www.cnblogs.com/lokiii/p/10453264.html
Copyright © 2011-2022 走看看