Description
题目背景:
尊者神高达很穷,所以他需要跑商来赚钱
题目描述:
基三的地图可以看做 n 个城市,m 条边的无向图,尊者神高达会从任意一个点出发并在起点购买货物,在旅途中任意一点卖出并最终到达终点,尊者神高达的时间很宝贵,所以他不会重复经过同一个城市,但是为了挣钱,他可能会去绕路。当然,由于工作室泛滥,所以一个城市的货物价格可能会发生改变。但是尊者神高达智商不足,他可能在一个很蠢的节点把货物卖掉,所以尊者神高达想知道每一次跑商最多能赔多少钱。
尊者神高达很穷,所以他需要跑商来赚钱
题目描述:
基三的地图可以看做 n 个城市,m 条边的无向图,尊者神高达会从任意一个点出发并在起点购买货物,在旅途中任意一点卖出并最终到达终点,尊者神高达的时间很宝贵,所以他不会重复经过同一个城市,但是为了挣钱,他可能会去绕路。当然,由于工作室泛滥,所以一个城市的货物价格可能会发生改变。但是尊者神高达智商不足,他可能在一个很蠢的节点把货物卖掉,所以尊者神高达想知道每一次跑商最多能赔多少钱。
Input
第一行 n,m;
接下来 1 行 n 个数,代表每个城市货物的价格;
接下来 m 行 u,v 代表一条边
接下来 1 行 Q
接下来 Q 行
C x w 代表城市 x 的货物价格变为 w
Q u v 代表一次从 u 到 v 的跑商
接下来 1 行 n 个数,代表每个城市货物的价格;
接下来 m 行 u,v 代表一条边
接下来 1 行 Q
接下来 Q 行
C x w 代表城市 x 的货物价格变为 w
Q u v 代表一次从 u 到 v 的跑商
Output
如题目描述
Sample Input
3 3 1 2 3 1 2 2 3 1 3 3 Q 2 3 C 1 5 Q 1 3
Sample Output
1 3 样例解释: 1,2,3 都联通,起点购买价格为 2,在 1 点卖出赔得最多2-1=1 更新后每个点价值为 5,2,3 起点价格为 5,在 2 点卖出赔得最多,5-2=3
Data Constraint
40%的数据为一棵树
另外 20%的数据没有修改操作
所以数据满足 n,m,q<=100000;保证图联通,数据合法
另外 20%的数据没有修改操作
所以数据满足 n,m,q<=100000;保证图联通,数据合法
Hint
Tips:数据很水可以尝试瞎搞算法,1,2 两道题算法我暑假讲过类似的,各位随便 AC,第三题应该有不少大佬见过原题 orz。
分析
原题怪!
这题我们转换成圆方树,然后对于方点,我们储存的值为所连叶子节点的最小值(虽然父亲也是环的一部分但是算进去很麻烦)用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; } } }