题面
https://www.luogu.org/problemnew/show/CF487E
1、$LCT$ 中,翻转懒标记,我是在打上的一刻同时进行翻转左右儿子,所以在 $makeroot(x)$ 的时候 $rev[x] oplus =1,swap(ch[x][0],ch[x][1])$
2、$LCT$ 中,处理子树信息时(此题没有涉及到),$makeroot(x)$ 即变成以x为根的有根树。(虽然这是$makeroot$真实的含义,但我还是觉得好神奇)
3、$LCT$ 中,初始化,每个节点形成一个子树,记得把节点维护的信息加进去。
4、$Tarjan(x)$时,判定点双的方程是$low[y]>=dfn[x]$,弹栈时把$y$弹出为止,并且把$x$连上去。
5、圆方树,有根化的小$trick$。
6、$mutiset$,删除相同的只删除一个。(所以此题才能放心删)
7、记一下结论吧,防止以后忘了。
- $rotate(x)$ 6(2判)+2;
- $splay(x)$ 遍历同一棵splay上的祖先+1特判+两种情况
- $access(x)$ 1+2+2
- $makeroot(x)$ 2+2+1
- $link(x)$ 2
#include<cstdio> #include<cstring> #include<iostream> #include<set> #include<vector> #include<stack> #define ri register int #define N 405000 using namespace std; int read() { int ret=0,f=0; char ch=getchar(); while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret=ret*10+(ch-'0'),ch=getchar(); return f?-ret:ret; } int tn,n,m,q; int w[N]; struct tree { vector<int> to[N]; int fa[N],d[N],f[N][20]; multiset<int> s[N]; void add_edge(int u,int v) { to[u].push_back(v); to[v].push_back(u); } void maketree(int x,int ff) { d[x]=d[ff]+1; f[x][0]=fa[x]=ff; for (ri i=1;i<=18;i++) f[x][i]=f[f[x][i-1]][i-1]; for (ri i=0;i<to[x].size();i++) { int y=to[x][i]; if (y==ff) continue; maketree(y,x); } } int lca(int u,int v) { if (d[u]<d[v]) swap(u,v); for (ri i=18;i>=0;i--) if (d[f[u][i]]>=d[v]) u=f[u][i]; if (u==v) return u; for (ri i=18;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return fa[u]; } void init(int x) { for (ri i=0;i<to[x].size();i++) { int y=to[x][i]; if (y==fa[x]) continue; s[x].insert(w[y]); } w[x]=*(s[x].begin()); } } T; struct link_cut_tree { bool rev[N]; int fa[N],poi[N]; int ch[N][2]; inline bool notroot(int x) { return ch[fa[x]][0]==x || ch[fa[x]][1]==x; } inline bool opt(int x) { return (ch[fa[x]][1]==x); } void pushup(int x) { poi[x]=x; if (ch[x][0] && w[poi[ch[x][0]]]<w[poi[x]]) poi[x]=poi[ch[x][0]]; if (ch[x][1] && w[poi[ch[x][1]]]<w[poi[x]]) poi[x]=poi[ch[x][1]]; } void pushr(int x) { if (!rev[x] || !x) return; rev[x]=0; if (ch[x][0]) swap(ch[ch[x][0]][0],ch[ch[x][0]][1]),rev[ch[x][0]]^=1; if (ch[x][1]) swap(ch[ch[x][1]][0],ch[ch[x][1]][1]),rev[ch[x][1]]^=1; } void rotate(int x) { int y=fa[x],z=fa[y],s=opt(x),w=ch[x][1^s]; fa[x]=z; if (notroot(y)) ch[z][opt(y)]=x; if (w) fa[w]=y; ch[y][s]=w; fa[y]=x; ch[x][1^s]=y; pushup(y); pushup(x); } void splay(int x) { int y=x; stack<int> stk; while (!stk.empty()) stk.pop(); while (notroot(y)) stk.push(y),y=fa[y]; stk.push(y); while (!stk.empty()) pushr(stk.top()),stk.pop(); while (notroot(x)) { int y=fa[x]; if (!notroot(y)) rotate(x); else if (opt(x)==opt(y)) rotate(y),rotate(x); else rotate(x),rotate(x); } } void access(int x) { int y=0; while (x) { splay(x); ch[x][1]=y; pushup(x); y=x; x=fa[x]; } } void makeroot(int x) { access(x); splay(x); rev[x]^=1; swap(ch[x][0],ch[x][1]); pushr(x); } void link(int u,int v) { makeroot(u); fa[u]=v; } } lct; struct graph { vector<int> to[N]; stack<int> stk; int tot; int dfn[N],low[N]; void add_edge(int u,int v) { to[u].push_back(v); to[v].push_back(u); } void tarjan(int x) { dfn[x]=low[x]=++tot; stk.push(x); for (ri i=0;i<to[x].size();i++) { int y=to[x][i]; if (dfn[y]) { low[x]=min(low[x],dfn[y]); } else { tarjan(y); low[x]=min(low[y],low[x]); if (low[y]>=dfn[x]) { ++n; int t; do { t=stk.top(); stk.pop(); T.add_edge(n,t); } while (t!=y); T.add_edge(n,x); } } } } } G; void change(int x,int v) { int y=T.fa[x]; T.s[y].erase(w[x]); lct.splay(x); w[x]=v; T.s[y].insert(w[x]); lct.splay(y); w[y]=*(T.s[y].begin()); } int query(int x,int y) { lct.makeroot(x); lct.access(y); lct.splay(y); int z=T.lca(x,y); if (z>tn) return min(w[lct.poi[y]],w[T.fa[z]]); return w[lct.poi[y]]; } int main(){ char opt[10]; tn=n=read(); m=read(); q=read(); memset(w,0x3f,sizeof(w)); for (ri i=1;i<=n;i++) w[i]=read(); for (ri i=1;i<=m;i++) { int u=read(),v=read(); G.add_edge(u,v); } G.tot=0; G.tarjan(1); T.maketree(1,1); for (ri i=1;i<=n;i++) { lct.poi[i]=i; if (T.fa[i]!=i) lct.link(T.fa[i],i); if (i>tn) T.init(i); } for (ri i=1;i<=q;i++) { scanf("%s",opt); int u=read(),v=read(); if (opt[0]=='A') printf("%d ",query(u,v)); else if (opt[0]=='C') change(u,v); } return 0; }