Tourists——圆方树
Posted miracevin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tourists——圆方树相关的知识,希望对你有一定的参考价值。
一般图,带修求所有简单路径代价。
简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了。
所以可以圆方树,然后方点维护一下V-DCC内的最小值。
那么,从任意一个割点进入这个DCC,必然可以绕一圈再从另一个割点出去。
所以,路径上的最小值,就是圆方树路径上的最小值。方点的最小值就是在这个DCC中走一走得到的。
树链剖分+线段树维护路径
用堆维护方点四周的圆点的最小值。然后更新。
一个问题是:
更新一个割点圆点,会影响到四周所有的方点。暴力更新,菊花图直接TLE
这样更新:
方点只维护圆方树上儿子圆点的最值。
这样,每次修改圆点,只要修改father的方点的值即可。
查询路径的时候,如果LCA是方点,那么把这个方点的father的值也取min即可。
圆点就无所谓了。LCA自己一定会取到的。
代码:
#include<bits/stdc++.h> #define reg register int #define mid ((l+r)>>1) #define il inline #define numb (ch^‘0‘) using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch==‘-‘)&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=2e5+5; const int inf=0x3f3f3f3f; int n,m,q; struct node{ int nxt,to; }e[2*N],bian[2*N]; int hd[N],pre[N]; int cnt1,cnt2; void _add(int x,int y){ bian[++cnt1].nxt=pre[x]; bian[cnt1].to=y; pre[x]=cnt1; } void add(int x,int y){ e[++cnt2].nxt=hd[x]; e[cnt2].to=y; hd[x]=cnt2; } struct heap{ priority_queue<int,vector<int>,greater<int> >h,d; int top(){ while(h.size()&&d.size()&&h.top()==d.top()){ h.pop();d.pop(); } if(h.empty()) return inf; return h.top(); } void push(int c){ h.push(c); } void dele(int c){ d.push(c); } }f[N]; int w[N]; int tot,df; int dfn[N],low[N],sta[N],tp; void tarjan(int x){ dfn[x]=low[x]=++df; sta[++tp]=x; for(reg i=pre[x];i;i=bian[i].nxt){ int y=bian[i].to; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]){ ++tot;//fang w[tot]=inf;//warning!!! int z; do{ z=sta[tp--]; add(tot,z);add(z,tot); }while(z!=y); add(x,tot);add(tot,x); } } else low[x]=min(low[x],dfn[y]); } } int dep[N],fa[N],top[N],fdfn[N],son[N],sz[N]; void dfs1(int x,int d){ dep[x]=d; sz[x]=1; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa[x]) continue; fa[y]=x; dfs1(y,d+1); sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; if(x>n){//a fang f[x].push(w[y]); w[x]=min(w[x],w[y]); } } } void dfs2(int x){ dfn[x]=++df; fdfn[df]=x; if(!top[x]) top[x]=x; if(son[x]) top[son[x]]=top[x],dfs2(son[x]); for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa[x]) continue; if(y==son[x]) continue; dfs2(y); } } int mi[4*N]; void pushup(int x){ mi[x]=min(mi[x<<1],mi[x<<1|1]); } void build(int x,int l,int r){ if(l==r){ mi[x]=w[fdfn[l]];return; } build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void chan(int x,int l,int r,int to,int c){ if(l==r){ mi[x]=c;return; } if(to<=mid) chan(x<<1,l,mid,to,c); else chan(x<<1|1,mid+1,r,to,c); pushup(x); } int query(int x,int l,int r,int L,int R){ if(L<=l&&r<=R){ return mi[x]; } int ret=inf; if(L<=mid) ret=min(ret,query(x<<1,l,mid,L,R)); if(mid<R) ret=min(ret,query(x<<1|1,mid+1,r,L,R)); return ret; } int wrk(int x,int y){ int ret=inf; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ret=min(ret,query(1,1,tot,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ret=min(ret,query(1,1,tot,dfn[y],dfn[x])); if(y>n) ret=min(ret,w[fa[y]]); return ret; } int main(){ rd(n);rd(m);rd(q); for(reg i=1;i<=n;++i)rd(w[i]); int x,y; for(reg i=1;i<=m;++i){ rd(x);rd(y); _add(x,y);_add(y,x); } tot=n; tarjan(1); memset(dfn,0,sizeof dfn); df=0; dfs1(1,1); dfs2(1); build(1,1,tot); char ch[10]; while(q--){ scanf("%s",ch+1); if(ch[1]==‘A‘){ rd(x);rd(y); printf("%d ",wrk(x,y)); } else{ rd(x);rd(y); int ff=fa[x]; f[ff].dele(w[x]); f[ff].push(y); int tmp=f[ff].top(); chan(1,1,tot,dfn[ff],tmp); w[ff]=tmp;//no use in fact w[x]=y; chan(1,1,tot,dfn[x],y); } } return 0; } } int main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/11/30 16:10:40 */
以上是关于Tourists——圆方树的主要内容,如果未能解决你的问题,请参考以下文章