基三的地图可以看做 n 个城市,m 条边的无向图,尊者神高达会从任意一个点出发并在起点购买货物,在旅途中任意一点卖出并最终到达终点,尊者神高达的时间很宝贵,所以他不会重复经过同一个城市,但是为了挣钱,他可能会去绕路。当然,由于工作室泛滥,所以一个城市的货物价格可能会发生改变。但是尊者神高达智商不足,他可能在一个很蠢的节点把货物卖掉,所以尊者神高达想知道每一次跑商最多能赔多少钱。
很容易想到答案为起点的值剪掉路径上最大值,然后问题就变成了求动态求路径最大值,如果是树的话直接树链剖分就好了,不是树的话就很难处理,我们机智的发现,一个环每条边都是可以走到的,所以我们可以用圆方树,方点为环上的最大值,然后发现好像维护不了,那我们改改定义,方点为儿子里面的最大值,这样如果lca是一个方点就还要特判断一下父亲节点。用平衡树来维护每个点的值。
程序:
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=400005;
struct tree{int to,next;}e[N*2];
struct tree1{int to,next;}e1[N*2];
int n,n1,n2,cnt,p,m,q,cnt1;
int last[N],pr[N],f[N],pt[N],st[N],size[N],son[N],ft[2*N],mi[N],dfn[N],last1[N],low[N],dep[N*2],top[N*2];
int t[N*2][2];
multiset<int> h[N];
void add(int x,int y){
e[++cnt].to=y; e[cnt].next=last[x]; last[x]=cnt;
e[++cnt].to=x; e[cnt].next=last[y]; last[y]=cnt;
}
void add1(int x,int y){
e1[++cnt1].to=y; e1[cnt1].next=last1[x]; last1[x]=cnt1;
e1[++cnt1].to=x; e1[cnt1].next=last1[y]; last1[y]=cnt1;
}
void tarjan(int x,int fa){
st[++st[0]]=x;
low[x]=dfn[x]=++dfn[0];
for(int i=last[x];i;i=e[i].next)
if (e[i].to!=fa){
if (!dfn[e[i].to]){
tarjan(e[i].to,x);
if (low[e[i].to]>=dfn[x]){
add1(++n1,x); ;
while (st[st[0]]!=e[i].to) add1(st[st[0]],n1),st[st[0]--]=0;
add1(n1,e[i].to),st[st[0]--]=0;
}
else low[x]=min(low[x],low[e[i].to]);
} else low[x]=min(low[x],dfn[e[i].to]);
}
}
void dfs(int x,int fa){
if (x<=n&&fa>n) h[fa].insert(pr[x]);
dep[x]=dep[fa]+1;
f[x]=fa;
size[x]=1;
for (int i=last1[x];i;i=e1[i].next)
if (e1[i].to!=fa){
dfs(e1[i].to,x);
size[x]+=size[e1[i].to];
if (size[e1[i].to]>size[son[x]]) son[x]=e1[i].to;
}
}
void build(int x,int l,int r){
mi[x]=1e9;
if (l==r) pt[l]=x;
else {
int mid=(l+r)>>1;
ft[t[x][0]=++n2]=x,build(n2,l,mid);
ft[t[x][1]=++n2]=x,build(n2,mid+1,r);
}
}
void ins(int x,int v){
mi[x]=v,x=ft[x];
while (x) mi[x]=min(mi[t[x][0]],mi[t[x][1]]),x=ft[x];
}
int query(int rt,int l,int r,int x,int y){
if (!rt||x>y||x>r||y<l) return 1e9;
if (x<=l&&r<=y) return mi[rt];
int mid=(l+r)>>1;
return min(query(t[rt][0],l,mid,x,y),query(t[rt][1],mid+1,r,x,y));
}
void make(int x){
if (!x) return;
dfn[x]=++dfn[0];
if (x>n) pr[x]=*h[x].begin();
ins(pt[dfn[x]],pr[x]);
top[son[x]]=top[x],make(son[x]);
for (int i=last1[x];i;i=e1[i].next)
if (e1[i].to!=f[x]&&e1[i].to!=son[x]){
top[e1[i].to]=e1[i].to,make(e1[i].to);
}
}
int get(int x,int y){
if (top[x]==top[y]){
if (dep[x]>dep[y]) swap(x,y);
int v=1e9;
if (x>n) v=pr[f[x]];
return min(v,query(1,1,n1,dfn[x],dfn[y]));
}
if (dep[top[x]]>dep[top[y]]) swap(x,y);
return min(get(x,f[top[y]]),query(1,1,n1,dfn[top[y]],dfn[y]));
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
// freopen("paoshang.in","r",stdin);
// freopen("paoshang.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&pr[i]);
for (int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
n1=n;
tarjan(1,0);
dfs(1,0);
n2=1;
memset(dfn,0,sizeof(dfn));
build(1,1,n1);
make(1);
scanf("%d",&q);
for (int i=1;i<=q;i++){
char ch;
scanf("\n%c",&ch);
int x,y;
scanf("%d%d",&x,&y);
if (ch=='Q') printf("%d\n",pr[x]-get(x,y));
else{
ins(pt[dfn[x]],y);
if (x>1){
int p=f[x];
h[p].erase(h[p].find(pr[x]));
h[p].insert(y);
int v=*h[p].begin();
if (v!=pr[p]){
pr[p]=v;
ins(pt[dfn[p]],pr[p]);
}
}
pr[x]=y;
}
}
}