题目背景:
尊者神高达很穷,所以他需要跑商来赚钱
题目描述:
基三的地图可以看做 n 个城市,m 条边的无向图,尊者神高达会从任意一个点出发并在起点购买货物,在旅途中任意一点卖出并最终到达终点,尊者神高达的时间很宝贵,所以他不会重复经过同一个城市,但是为了挣钱,他可能会去绕路。当然,由于工作室泛滥,所以一个城市的货物价格可能会发生改变。但是尊者神高达智商不足,他可能在一个很蠢的节点把货物卖掉,所以尊者神高达想知道每一次跑商最多能赔多少钱。
sol:
这不是圆方树模板题嘛
发现一个点双内的点可以全部取到
于是直接把圆方树建出来,然后方点用multiset维护一个圆点的最小值
但是这样发现如果直接更新的话,要更新一圈圆点,所以考虑方点不维护它父亲的值,而是只维护儿子中的圆点值
然后接下来的问题就是路径最值问题了
树上路径最值,显然树链剖分
然后我们就做完了
lca是方点的时候记得找一下父亲==
[然后今早tarjan把v写成u,然后就自闭了.jpg]
[然后还忘记保存本来的x值了……]
[自闭选手不配ac]
#include <bits/stdc++.h> using namespace std; int cnt1,nex1[500005],las1[500005],Arrive1[500005],cnt2,nex2[500005],las2[500005],Arrive2[500005]; int N,M,Q,Bcc_cnt; int w[500005]; multiset<int> S[500005]; int dfn[500005],Low[500005],Timew; int stk[500005],tp; void jt1(int x,int y){ cnt1++; nex1[cnt1]=las1[x]; las1[x]=cnt1; Arrive1[cnt1]=y; } void jt2(int x,int y){ cnt2++; nex2[cnt2]=las2[x]; las2[x]=cnt2; Arrive2[cnt2]=y; } void Tarjan(int Now){ //cout<<Now<<endl; Low[Now]=dfn[Now]=++Timew; stk[++tp]=Now; for (int i=las1[Now];i;i=nex1[i]){ if (!dfn[Arrive1[i]]){ Tarjan(Arrive1[i]); Low[Now]=min(Low[Now],Low[Arrive1[i]]); if (Low[Arrive1[i]]==dfn[Now]){ ++Bcc_cnt; for (int x=0;x!=Arrive1[i];--tp){ x=stk[tp]; jt2(Bcc_cnt,x); jt2(x,Bcc_cnt); } jt2(Bcc_cnt,Now); jt2(Now,Bcc_cnt); } } else Low[Now]=min(Low[Now],dfn[Arrive1[i]]); } } int idf[500005],fa[500005],Siz[500005],dep[500005],Son[500005],top[500005],dfc; void dfs1(int Now,int Fa){ fa[Now]=Fa;dep[Now]=dep[Fa]+1;Siz[Now]=1; for (int i=las2[Now];i;i=nex2[i]) if (Arrive2[i]!=Fa){ dfs1(Arrive2[i],Now); Siz[Now]+=Siz[Arrive2[i]]; if (Siz[Son[Now]]<Siz[Arrive2[i]]) Son[Now]=Arrive2[i]; } } void dfs2(int Now,int Fa,int tp){ dfn[Now]=++dfc,idf[dfc]=Now,top[Now]=tp; if (Son[Now]) dfs2(Son[Now],Now,tp); for (int i=las2[Now];i;i=nex2[i]) if (Arrive2[i]!=Fa&&Arrive2[i]!=Son[Now]) dfs2(Arrive2[i],Now,Arrive2[i]); } int Tree[1000005]; void Build(int Now,int l,int r){ if (l==r) {Tree[Now]=w[idf[l]]; return;} int mid=(l+r)>>1; Build(Now<<1,l,mid),Build(Now<<1|1,mid+1,r); Tree[Now]=min(Tree[Now<<1],Tree[Now<<1|1]); } void Modify(int Now,int l,int r,int Pos,int x){ if (l==r) {Tree[Now]=x;return;} int mid=(l+r)>>1; if (Pos<=mid) Modify(Now<<1,l,mid,Pos,x); else Modify(Now<<1|1,mid+1,r,Pos,x); Tree[Now]=min(Tree[Now<<1],Tree[Now<<1|1]); } int query(int Now,int l,int r,int L,int R){ if (r<L||l>R) return 1e9+7; if (L<=l&&r<=R) return Tree[Now]; int mid=(l+r)>>1; return min(query(Now<<1,l,mid,L,R),query(Now<<1|1,mid+1,r,L,R)); } 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",&w[i]); Bcc_cnt=N; for (int i=1;i<=M;i++){ int u,v; scanf("%d%d",&u,&v); jt1(u,v); jt1(v,u); } Tarjan(1),dfs1(1,0),dfc=0,dfs2(1,0,1); for (int i=1;i<=N;i++) if (fa[i]) S[fa[i]].insert(w[i]); for (int i=N+1;i<=Bcc_cnt;i++) w[i]=*S[i].begin(); Build(1,1,Bcc_cnt); scanf("%d",&Q); while (Q--){ char opt[3];int x,y; scanf("%s%d%d",opt,&x,&y); if (*opt=='C'){ Modify(1,1,Bcc_cnt,dfn[x],y); if (fa[x]){ int u=fa[x]; S[u].erase(S[u].lower_bound(w[x])); S[u].insert(y); if (w[u]!=*S[u].begin()){ w[u]=*S[u].begin(); Modify(1,1,Bcc_cnt,dfn[u],w[u]); } } w[x]=y; } else{ int Ans=1e9+7,qwq=x; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); Ans=min(Ans,query(1,1,Bcc_cnt,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if (dfn[x]>dfn[y]) swap(x,y); Ans=min(Ans,query(1,1,Bcc_cnt,dfn[x],dfn[y])); if (x>N) Ans=min(Ans,w[fa[x]]); printf("%d ",w[qwq]-Ans); } } }