CF487E Tourists (圆方树,LCT)
圆方树模板题.
建出圆方树.
对于每个方点,只维护方点儿子的最小值,不维护方点父亲的值,这样的话每次修改只会改一个方点.
我们需要支持单点修改,链查询,求 lca.
LCT 可以非常方便地维护这些东西,然后如果 lca 是方点的话特判一下方点父亲的点值即可,可以单独开一个命名空间以防止变量名冲突。
code:
#include <cstdio> #include <algorithm> #include <set> #include <vector> #include <cstring> #define setI(s) freopen(s".in","r",stdin) #define setO(s) freopen(s".out","w",stdout) #define setIO(s) setI(s),setO(s) using namespace std; const int N=2e5+5; const int inf=1e9+2; namespace lct { #define lson s[x].ch[0] #define rson s[x].ch[1] struct data { int ch[2],rev,val,mi,f; data(int x=inf) { ch[0]=ch[1]=0,val=mi=x; } }s[N]; int sta[N]; int get(int x) { return s[s[x].f].ch[1]==x; } int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; } void pushup(int x) { s[x].mi=min(s[x].val,min(s[lson].mi,s[rson].mi)); } void mark(int x) { if(!x) return; swap(lson,rson),s[x].rev^=1; } void pushdown(int x) { if(s[x].rev) mark(lson),mark(rson),s[x].rev=0; } void rotate(int x) { int old=s[x].f,fold=s[old].f,which=get(x); if(!isr(old)) s[fold].ch[s[fold].ch[1]==old]=x; s[old].ch[which]=s[x].ch[which^1]; if(s[old].ch[which]) s[s[old].ch[which]].f=old; s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold; pushup(old),pushup(x); } void splay(int x) { int u=x,v=0,fa; for(sta[++v]=u;!isr(u);u=s[u].f) sta[++v]=s[u].f; for(;v;--v) pushdown(sta[v]); for(u=s[u].f;(fa=s[x].f)!=u;rotate(x)) if(s[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } int Access(int x) { int y=0; for(;x;y=x,x=s[x].f) splay(x),rson=y,pushup(x); return y; } void makert(int x) { Access(x),splay(x),mark(x); } void split(int x,int y) { makert(x),Access(y),splay(y); } void link(int x,int y) { s[x].f=y; } int get_lca(int x,int y) { Access(x); return Access(y); } }; vector<int>G[N]; int val[N],dfn[N],low[N],S[N],tim,top,tot; int hd[N],to[N],nex[N],edges,n,m,Q; int fa[N]; multiset<int>mi[N]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void tarjan(int u) { dfn[u]=low[u]=++tim; S[++top]=u; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(!dfn[v]) { tarjan(v),low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { ++tot; G[tot].push_back(u); G[u].push_back(tot); for(int x=0;x!=v;--top) { x=S[top]; G[tot].push_back(x); G[x].push_back(tot); } } } else low[u]=min(low[u],dfn[v]); } } void dfs(int x,int ff) { if(ff) lct::link(x,ff); if(x<=n) { if(ff) mi[ff].insert(val[x]); lct::s[x].val=lct::s[x].mi=val[x]; } for(int i=0;i<G[x].size();++i) { int y=G[x][i]; if(y!=ff) fa[y]=x,dfs(y,x); } if(x>n) { lct::s[x].val=lct::s[x].mi=*mi[x].begin(); } } int main() { //setI("input"); scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=n;++i) scanf("%d",&val[i]); for(int i=1;i<=m;++i) { int x,y; scanf("%d%d",&x,&y); add(x,y),add(y,x); } tot=n; for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); dfs(1,0); val[0]=inf; for(int i=1;i<=Q;++i) { char ch[2]; int x,b; scanf("%s%d%d",ch,&x,&b); if(ch[0]=='C') { lct::splay(x); lct::s[x].val=b; lct::pushup(x); if(fa[x]) { mi[fa[x]].erase(mi[fa[x]].lower_bound(val[x])); mi[fa[x]].insert(b); lct::splay(fa[x]); lct::s[fa[x]].val=*mi[fa[x]].begin(); lct::pushup(fa[x]); } val[x]=b; // modify(val[x] -> b) } else { // query(a,b) int lca=lct::get_lca(x,b); if(lca<=n) lca=0; lct::split(x,b); printf("%d\n",min(lct::s[b].mi,val[fa[lca]])); lct::makert(1); } } return 0; }