版权声明:转载者乖乖♂站好 https://blog.csdn.net/Eric1561759334/article/details/83118824
Description
题目背景:
尊者神高达很穷,所以他需要跑商来赚钱
题目描述:
基三的地图可以看做 n 个城市,m 条边的无向图,尊者神高达会从任意一个点出发并在起点购买货物,在旅途中任意一点卖出并最终到达终点,尊者神高达的时间很宝贵,所以他不会重复经过同一个城市,但是为了挣钱,他可能会去绕路。当然,由于工作室泛滥,所以一个城市的货物价格可能会发生改变。但是尊者神高达智商不足,他可能在一个很蠢的节点把货物卖掉,所以尊者神高达想知道每一次跑商最多能赔多少钱。
Input
第一行 n,m;
接下来 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;保证图联通,数据合法
思路
建一棵广义圆方树
每个方点记录左右与其相连的原点的最小值
然后发现如果是棵菊花树就炸了
所以方点的值改为记录环上除根外权值最小的点。如果 LCA是方点,只需特判一下方点的父亲。这样修改就是 o(2)的了
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#define maxn 2000010
using namespace std;
struct E
{
int to,next;
}e[maxn*2],ee[maxn*2];
int n,m,v[maxn],num1,num2,cnt,cnt1,dfn[maxn],low[maxn],list[maxn],list1[maxn],top[maxn],dep[maxn],fa[maxn],size[maxn],son[maxn],l[2*maxn][2],p[2*maxn],tree[maxn],n2,mn[2*maxn],q[maxn];
multiset<int>Q[maxn];
using namespace std;
void add(int x,int y)
{
e[++cnt].to=y; e[cnt].next=list[x]; list[x]=cnt;
}
void add1(int x,int y)
{
ee[++cnt1].to=y; ee[cnt1].next=list1[x]; list1[x]=cnt1;
}
void tarjan(int x,int fa)
{
q[++q[0]]=x,dfn[x]=low[x]=++dfn[0];
for(int i=list[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(++num1,x),add1(x,num1);
while(q[q[0]]!=e[i].to) add1(num1,q[q[0]]),add1(q[q[0]],num1),q[q[0]--]=0;
add1(num1,e[i].to),add1(e[i].to,num1),q[q[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 pre)
{
dep[x]=dep[pre]+1,fa[x]=pre,size[x]=1;
if(x<=n&&pre>n) Q[pre].insert(v[x]);
for(int i=list1[x]; i; i=ee[i].next)
if(ee[i].to!=pre)
{
dfs(ee[i].to,x),size[x]+=size[ee[i].to];
if(size[ee[i].to]>size[son[x]]) son[x]=ee[i].to;
}
}
void build(int d,int x,int y)
{
mn[d]=1e9;
if(x==y) { tree[x]=d; return; }
int mid=(x+y)>>1;
p[l[d][0]=++num2]=d,build(num2,x,mid);
p[l[d][1]=++num2]=d,build(num2,mid+1,y);
}
void ins(int x,int y)
{
mn[x]=y,x=p[x];
while(x) mn[x]=min(mn[l[x][0]],mn[l[x][1]]),x=p[x];
}
void dfs1(int x)
{
if(!x) return;
dfn[x]=++dfn[0];
if(x>n) v[x]=*Q[x].begin();
ins(tree[dfn[x]],v[x]);
top[son[x]]=top[x],dfs1(son[x]);
for(int i=list1[x]; i; i=ee[i].next)
if(ee[i].to!=fa[x]&&ee[i].to!=son[x])
top[ee[i].to]=ee[i].to,dfs1(ee[i].to);
}
int query(int d,int L,int R,int x,int y)
{
if(!d||x>y||x>R||y<L) return 1e9;
if(x<=L&&R<=y) return mn[d];
int mid=(L+R)>>1;
return min(query(l[d][0],L,mid,x,y),query(l[d][1],mid+1,R,x,y));
}
int work(int x,int y)
{
if(top[x]==top[y])
{
if(dep[x]>dep[y]) swap(x,y);
int k=1e9;
if(x>n) k=v[fa[x]];
return min(k,query(1,1,num1,dfn[x],dfn[y]));
}
if(dep[top[x]]>dep[top[y]]) swap(x,y);
return min(work(x,fa[top[y]]),query(1,1,num1,dfn[top[y]],dfn[y]));
}
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",&v[i]);
for(int i=1,x,y; i<=m; i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
num1=n,tarjan(1,0);
dfs(1,0);
num2=1,build(1,1,num1);
memset(dfn,0,sizeof(dfn)),dfs1(1);
int x,y,o;
scanf("%d",&o);
while(o--)
{
scanf("\n");
char ch=getchar();
scanf("%d%d",&x,&y);
if(ch=='Q') printf("%d\n",v[x]-work(x,y));
else
{
ins(tree[dfn[x]],y);
if(x>1)
{
int k=fa[x];
Q[k].erase(Q[k].find(v[x])),Q[k].insert(y);
int o=*Q[k].begin();
if(v[k]!=o) v[k]=o,ins(tree[dfn[k]],v[k]);
}
v[x]=y;
}
}
}