Description

Cyberland 有 n 座城市,编号从 1 到 n,有 m 条双向道路连接这些城市。第 j 条路连接城市 aj 和 bj。每天,都有成千上万的游客来到 Cyberland 游玩。

在每一个城市,都有纪念品售卖,第 i 个城市售价为 wi。这个售价有时会变动。

每一个游客的游览路径都有固定起始城市和终止城市,且不会经过重复的城市。

他们会在路径上的城市中,售价最低的那个城市购买纪念品。

你能求出每一个游客在所有合法的路径中能购买的最低售价是多少吗?

你要处理 q个操作:

C a w: 表示 a 城市的纪念品售价变成 w。

A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值。

Solution

\(tarjan\)求出双连通分量,建立圆方树,然后答案就是圆方树上两点间的经过的点的最小值,树链剖分维护即可

方点本来是所有相邻圆点的权值最小值,此题中带修改,考虑维护一个父子关系,每次修改就只需要改父亲的方点即可

注意树链剖分查询时,如果链顶是方点,还需要查询其父亲的方点的权值,因为这个方点也属于这个双连通分量

方点的权值改用堆维护即可

#include <bits/stdc++.h>
#define ls (o<<1)
#define rs (o<<1|1)
using namespace std;
const int N=2e5+10,inf=1e9+10;
int n,m,Q,a[N],head[N],nxt[N<<2],to[N<<2],num=0,st[N],cnt=0,dep[N],Head[N];
int low[N],dfn[N],DFN=0,W,sz[N],son[N],fa[N],top[N],tr[N<<2],id[N],b[N];
struct H{
priority_queue<int>d,s;
inline void upd(){
while(!s.empty() && !d.empty() && s.top()==d.top())s.pop(),d.pop();
}
inline void push(int x){s.push(-x);}
inline void del(int x){d.push(-x);}
inline int top(){upd();return -s.top();}
}q[N];
inline void link(int x,int y){
nxt[++num]=head[x];to[num]=y;head[x]=num;
nxt[++num]=head[y];to[num]=x;head[y]=num;
}
inline void link2(int x,int y){
nxt[++num]=Head[x];to[num]=y;Head[x]=num;
nxt[++num]=Head[y];to[num]=x;Head[y]=num;
}
inline void tarjan(int x,int last){
low[x]=dfn[x]=++DFN;st[++cnt]=x;
for(int i=head[x];i;i=nxt[i]){
int u=to[i];if(u==last)continue;
if(!dfn[u]){
tarjan(u,x);
low[x]=min(low[x],low[u]);
if(low[u]>=dfn[x]){
link2(++n,x);a[n]=inf;
while(st[cnt]!=u)link2(n,st[cnt--]);
link2(n,st[cnt--]);
}
}
else low[x]=min(low[x],dfn[u]);
}
}
inline void dfs1(int x){
sz[x]=1;
for(int i=Head[x];i;i=nxt[i]){
int u=to[i];
if(sz[u])continue;
if(x>W)q[x].push(a[u]);
dep[u]=dep[x]+1;fa[u]=x;dfs1(u);sz[x]+=sz[u];
if(sz[u]>sz[son[x]])son[x]=u;
}
}
inline void dfs2(int x,int tp){
top[x]=tp;id[x]=++DFN;b[DFN]=x;
if(son[x])dfs2(son[x],tp);
for(int i=Head[x];i;i=nxt[i])
if(to[i]!=son[x] && to[i]!=fa[x])dfs2(to[i],to[i]);
}
inline void build(int l,int r,int o){
if(l==r){tr[o]=a[b[l]];return ;}
int mid=(l+r)>>1;
build(l,mid,ls);build(mid+1,r,rs);
tr[o]=min(tr[ls],tr[rs]);
}
inline void Modify(int l,int r,int o,int sa,int t){
if(l==r){tr[o]=t;return ;}
int mid=(l+r)>>1;
if(sa<=mid)Modify(l,mid,ls,sa,t);
else Modify(mid+1,r,rs,sa,t);
tr[o]=min(tr[ls],tr[rs]);
}
inline void updata(int x,int y){
if(fa[x]){
q[fa[x]].del(a[x]);q[fa[x]].push(y);
Modify(1,n,1,id[fa[x]],a[fa[x]]=q[fa[x]].top());
}
a[x]=y;Modify(1,n,1,id[x],y);
}
inline int qry(int l,int r,int o,int sa,int se){
if(sa<=l && r<=se)return tr[o];
int mid=(l+r)>>1;
if(se<=mid)return qry(l,mid,ls,sa,se);
else if(sa>mid)return qry(mid+1,r,rs,sa,se);
else return min(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se));
}
inline int query(int x,int y){
int ret=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ret=min(ret,qry(1,n,1,id[top[x]],id[x]));
x=fa[top[x]];
}
if(id[x]>id[y])swap(x,y);
ret=min(ret,qry(1,n,1,id[x],id[y]));
if(x>W)ret=min(ret,a[fa[x]]);
return ret;
}
int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
int x,y;char S[3];W=n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
link(x,y);
}
tarjan(1,1);
DFN=0;dfs1(1);dfs2(1,1);
for(int i=W+1;i<=n;i++)a[i]=q[i].top();
build(1,n,1);
while(Q--){
scanf("%s%d%d",S,&x,&y);
if(S[0]=='C')updata(x,y);
else printf("%d\n",query(x,y));
}
return 0;
}

UOJ #30. 【CF Round #278】Tourists的更多相关文章

  1. UOJ #30【CF Round #278】Tourists

    求从$ x$走到$ y$的路径上可能经过的最小点权,带修改  UOJ #30 $ Solution:$ 如果两个点经过了某个连通分量,一定可以走到这个连通分量的最小值 直接构建圆方树,圆点存原点的点权 ...

  2. UOJ30——【CF Round #278】Tourists

    1.感谢taorunz老师 2.题目大意:就是给个带权无向图,然后有两种操作, 1是修改某个点的权值 2是询问,询问一个值,就是u到v之间经过点权的最小值(不可以经过重复的点) 操作数,点数,边数都不 ...

  3. 【题解】【CF Round #278】Tourists

    圆方树第二题…… 图中询问的是指定两点之间简单路径上点的最小权值.若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值).我们可以发现其实就是这两点 ...

  4. uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)

    - 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...

  5. UOJ #30. [CF Round #278] Tourists

    UOJ #30. [CF Round #278] Tourists 题目大意 : 有一张 \(n\) 个点, \(m\) 条边的无向图,每一个点有一个点权 \(a_i\) ,你需要支持两种操作,第一种 ...

  6. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

  7. UOJ #269. 【清华集训2016】如何优雅地求和

    UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...

  8. UOJ #449. 【集训队作业2018】喂鸽子

    UOJ #449. [集训队作业2018]喂鸽子 小Z是养鸽子的人.一天,小Z给鸽子们喂玉米吃.一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米.一只鸽子饱了当且仅当它吃了的玉米粒数量\(≥ ...

  9. [UOJ#276]【清华集训2016】汽水

    [UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...

随机推荐

  1. 听翁恺老师mooc笔记(13)--类型定义和联合

    typedef 虽然我们知道使用struct这个关键字定义一个结构类型,然后可以使用该结构类型定义变量.但是每次要使用的时候都需要带着struct这个关键字,那么如何摆脱这个关键字哪?C语言提供了一个 ...

  2. 微信APP简要分析

    Part1 走进微信APP 很明显,微信是很成功的APP. 微信 (WeChat) 是腾讯公司于2011年1月21日推出的一个为智能终端提供即时通讯服务的免费应用程序,现已是超过九亿人使用的手机应用. ...

  3. Echarts柱状图实现不同颜色渐变色

    第一次写文,只是想记录一下自己平时发现的小功能,这篇主要是实现echarts柱状图,每个柱子实现不同颜色的渐变色,也是第一次接触echarts,后台使用ssm,前台是extjs,直接上效果图 直接上j ...

  4. signalR 消息推送

    业务情景一:上传报表,上传excel.如果excel的数据量很大,上万条,上十万条数据,那么这个上传请求必然是个耗时请求.用户上传之后,很关心上传的进度和结果. 业务情景二:站内消息提醒,实时有效地接 ...

  5. [译]RabbitMQ教程C#版 - 工作队列

    先决条件 本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难,可以 ...

  6. ELK学习总结(2-2)单模式CRUD操作

    ------------------------------------------------------ 1.查看索引信息 请求命令: GET /library/_settings GET /li ...

  7. GIT入门笔记(5)- 创建版本库

    版本库又名仓库,英文名repository,可以简单理解成一个目录, 这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻 ...

  8. 新概念英语(1-41)Penny's bag

    新概念英语(1-41)Penny's bag Who is the tin of tobacco for? A:Is that bag heavy, Penny? B:Not very. A:Here ...

  9. 使用Spring Initializr创建项目

    Spring initializr 是Spring 官方提供的一个很好的工具,可以用来用来创建一个Spring boot 的项目.可以选择使用Maven管理或者使用Gradle管理,还可以选择使用的编 ...

  10. Python面向对象进阶示例--自定义数据类型

    需求: 基于授权定制自己的列表类型,要求定制的自己的__init__方法, 定制自己的append:只能向列表加入字符串类型的值 定制显示列表中间那个值的属性(提示:property) 其余方法都使用 ...