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;保证图联通,数据合法
Solution
-
40%的数据就是裸的树链剖分,查询区间最小值、单点修改即可。
-
而变成无向图后呢,就要用到圆方树了!
-
圆方树是处理仙人掌的利器,应用广泛。
-
嗯,首先,它是一棵树,由圆点和方点组成。
-
原图中就存在的点被称为圆点,我们将其缩点双联通分量后,新建一个方点来代表这个点双,
-
并将点双中的点与这个方点连边(原来点双里面的边就不要了),缩点双用 tarjan 算法。
-
建出来的圆方树的圆点和方点是相隔的,即不会有圆点连圆点、方点连方点。
-
有了这颗圆方树,我们就能解决很多问题了!
-
在本题中,圆点的权值就设为其本来的值(即 a i a_i ai),而方点的值就是点双中点权的最小值。
-
注意: 这里方点的值不包括其父亲圆点的(这样好算很多)。
-
于是查询就能用树链剖分求最小值了,注意若两点lca是方点,还得算上其父亲圆点的值。
-
而查询的话,对于该圆点就单点修改,对于其属于的方点就用一个set(可维护插入删除,求最小值的数据结构)维护其包含的圆点值即可。
-
时间复杂度 O ( n l o g 2 n ) O(n\ log^2n) O(n log2n) 。
Code
#include<cstdio>
#include<algorithm>
#include<set>
#include<cctype>
using namespace std;
const int N=1e5+5,inf=1e9;
int n,m,tot=1,num,cnt,rt,qx,qy,stop,ans;
int first[N],nex[N<<1],en[N<<1];
int first1[N<<1],nex1[N<<1],en1[N<<1],d[N<<1];
int a[N];
int dfn[N],low[N],st[N],id[N];
int fa[N<<1],dep[N<<1],size[N<<1],son[N<<1];
int top[N<<1],tree[N<<1],pre[N<<1],f[N<<3];
multiset<int>ss[N<<1];
multiset<int>::iterator it;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
return w?-X:X;
}
inline void insert(int x,int y)
{
nex[++tot]=first[x];
first[x]=tot;
en[tot]=y;
}
inline void insert1(int x,int y)
{
nex1[++tot]=first1[x];
first1[x]=tot;
en1[tot]=y;
d[y]++;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
void tarjan(int x,int y)
{
dfn[x]=low[x]=++num;
st[++stop]=x;
for(int i=first[x];i;i=nex[i])
if(!dfn[en[i]])
{
tarjan(en[i],i^1);
low[x]=min(low[x],low[en[i]]);
if(low[en[i]]>=dfn[x])
{
cnt++;
do
{
id[st[stop]]=cnt;
insert1(cnt,st[stop]);
ss[cnt].insert(a[st[stop]]);
}while(st[stop--]^en[i]);
insert1(x,cnt);
}
}else
if(i^y) low[x]=min(low[x],dfn[en[i]]);
}
void dfs(int x)
{
dep[x]=dep[fa[x]]+1;
size[x]=1;
for(int i=first1[x];i;i=nex1[i])
if(en1[i]^fa[x])
{
fa[en1[i]]=x;
dfs(en1[i]);
size[x]+=size[en1[i]];
if(!son[x] || size[son[x]]<size[en1[i]]) son[x]=en1[i];
}
}
void dfs1(int x,int y)
{
top[pre[tree[x]=++num]=x]=y;
if(!son[x]) return;
dfs1(son[x],y);
for(int i=first1[x];i;i=nex1[i])
if(en1[i]^fa[x] && en1[i]^son[x]) dfs1(en1[i],en1[i]);
}
void make(int v,int l,int r)
{
if(l==r)
{
if(pre[l]>n)
{
it=ss[pre[l]].begin();
f[v]=*it;
}else f[v]=a[pre[l]];
return;
}
int mid=l+r>>1;
make(v<<1,l,mid);
make(v<<1|1,mid+1,r);
f[v]=min(f[v<<1],f[v<<1|1]);
}
int find(int v,int l,int r)
{
if(qx<=l && r<=qy) return f[v];
int mid=l+r>>1;
int s=inf;
if(qx<=mid) s=find(v<<1,l,mid);
if(qy>mid) s=min(s,find(v<<1|1,mid+1,r));
return s;
}
void change(int v,int l,int r)
{
if(l==r)
{
f[v]=qy;
return;
}
int mid=l+r>>1;
if(qx<=mid) change(v<<1,l,mid); else change(v<<1|1,mid+1,r);
f[v]=min(f[v<<1],f[v<<1|1]);
}
int main()
{
freopen("paoshang.in","r",stdin);
freopen("paoshang.out","w",stdout);
n=cnt=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
insert(x,y);
insert(y,x);
}
tarjan(1,tot=0);
for(int i=1;i<=cnt;i++)
if(!d[i])
{
rt=i;
break;
}
dfs(rt);
num=0;
dfs1(rt,rt);
make(1,1,num);
int q=read();
while(q--)
{
char ch=getchar();
while(ch^'Q' && ch^'C') ch=getchar();
if(ch=='Q')
{
int x=read(),y=read(),st=a[x];
ans=inf;
int f1=top[x],f2=top[y];
while(f1^f2)
{
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
qx=tree[f1],qy=tree[x];
ans=min(ans,find(1,1,num));
x=fa[f1],f1=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
qx=tree[x],qy=tree[y];
ans=min(ans,find(1,1,num));
if(x>n) ans=min(ans,a[fa[x]]);
printf("%d\n",st-ans);
}else
{
int x=read(),w=read();
qx=tree[x],qy=w;
change(1,1,num);
int y=id[x];
if(y)
{
it=ss[y].find(a[x]);
ss[y].erase(it);
ss[y].insert(w);
it=ss[y].begin();
qx=tree[y],qy=*it;
change(1,1,num);
}
a[x]=w;
}
}
return 0;
}