[圆方树][树链剖分][set]JZOJ 5909 跑商
分析
原题怪!
这题我们转换成圆方树,然后对于方点,我们储存的值为所连叶子节点的最小值(虽然父亲也是环的一部分但是算进去很麻烦)用set维护
然后树链剖分即可
对于LCA为方点的特殊情况,我们要特判一下它的父亲
#include <iostream> #include <cstdio> #include <set> #include <stack> using namespace std; const int N=1e6+10; struct Node { int sz,son,top,fa,seg,dep,w; }t[N]; int rev[N],scnt; struct Edge { int u,v,nx; }g[4*N],e[2*N]; int cnt,elist[N],list[2*N]; int s[4*N]; int low[N],dfn[N],tme; stack<int> stk; multiset<int> sqr[N]; int sqcnt; int n,m,q; void Adde(int u,int v) { e[++cnt].u=u;e[cnt].v=v;e[cnt].nx=elist[u];elist[u]=cnt; } void Add(int u,int v) { g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt; } void Tarjan(int u,int fa) { low[u]=dfn[u]=++tme;stk.push(u); for (int i=elist[u];i;i=e[i].nx) if (e[i].v!=fa) if (!dfn[e[i].v]) { Tarjan(e[i].v,u); if (low[e[i].v]>=dfn[u]) { Add(++sqcnt,u);Add(u,sqcnt); while (!stk.empty()&&stk.top()!=e[i].v) Add(sqcnt,stk.top()),Add(stk.top(),sqcnt),stk.pop(); Add(sqcnt,e[i].v),Add(e[i].v,sqcnt),stk.pop(); } else low[u]=min(low[u],low[e[i].v]); } else low[u]=min(low[u],dfn[e[i].v]); } void Dfs1(int u,int fa) { t[u].fa=fa;t[u].sz=1;t[u].dep=t[fa].dep+1; if (fa>n) sqr[fa-n].insert(t[u].w); for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) { Dfs1(g[i].v,u); t[u].sz+=t[g[i].v].sz; if (t[g[i].v].sz>t[t[u].son].sz) t[u].son=g[i].v; } } void Dfs2(int u,int fa) { int son=t[u].son; if (u>n) t[u].w=*sqr[u-n].begin(); if (son) { t[son].seg=++scnt; rev[scnt]=son; t[son].top=t[u].top; Dfs2(son,u); } for (int i=list[u];i;i=g[i].nx) if (!t[g[i].v].top) { t[g[i].v].seg=++scnt; rev[scnt]=g[i].v; t[g[i].v].top=g[i].v; Dfs2(g[i].v,u); } } void Build(int l,int r,int x) { if (l==r) { s[x]=t[rev[l]].w; return; } int mid=l+r>>1; Build(l,mid,x<<1);Build(mid+1,r,(x<<1)+1); s[x]=min(s[x<<1],s[(x<<1)+1]); } void Change(int l,int r,int w,int k,int x) { if (l>k||k>r) return; if (l==r&&r==k) { s[x]=w; return; } int mid=l+r>>1; if (mid>=k) Change(l,mid,w,k,x<<1); if (mid<k) Change(mid+1,r,w,k,(x<<1)+1); s[x]=min(s[x<<1],s[(x<<1)+1]); } int Query_Seg(int l,int r,int ll,int rr,int x) { if (l>rr||ll>r) return 2147483647; if (ll<=l&&r<=rr) return s[x]; int mid=l+r>>1,ans=2147483647; if (ll<=mid) ans=Query_Seg(l,mid,ll,rr,x<<1); if (mid<rr) ans=min(ans,Query_Seg(mid+1,r,ll,rr,(x<<1)+1)); return ans; } int Query_Tree(int x,int y) { int fx=t[x].top,fy=t[y].top; int ans=2147483647; while (fx!=fy) { if (t[fx].dep<t[fy].dep) swap(x,y),swap(fx,fy); ans=min(ans,Query_Seg(1,scnt,t[fx].seg,t[x].seg,1)); x=t[fx].fa;fx=t[x].top; } if (t[x].dep>t[y].dep) swap(x,y); return min(min(ans,x>n?t[t[x].fa].w:2147483647),Query_Seg(1,scnt,t[x].seg,t[y].seg,1)); } int main() { freopen("paoshang.in","r",stdin); freopen("paoshang.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&t[i].w); for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); Adde(u,v);Adde(v,u); } sqcnt=n;cnt=0;Tarjan(1,0); Dfs1(1,0); scnt=rev[1]=t[1].top=t[1].seg=1; Dfs2(1,0); Build(1,scnt,1); scanf("%d",&q); for (int i=1;i<=q;i++) { char c; do { scanf("%c",&c); } while (c!='Q'&&c!='C'); int u,v; scanf("%d%d",&u,&v); if (c=='Q') printf("%d\n",t[u].w-Query_Tree(u,v)); else { Change(1,scnt,v,t[u].seg,1); if (t[u].fa>n) { sqr[t[u].fa-n].erase(sqr[t[u].fa-n].find(t[u].w)); sqr[t[u].fa-n].insert(v); int fake=*sqr[t[u].fa-n].begin(); if (t[t[u].fa].w!=fake) t[t[u].fa].w=fake,Change(1,scnt,fake,t[t[u].fa].seg,1); } t[u].w=v; } } }
在日渐沉没的世界里,我发现了你。