【题解】【CF Round #278】Tourists
圆方树第二题……
图中询问的是指定两点之间简单路径上点的最小权值。若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值)。我们可以发现其实就是这两点在圆方树上经过的点的最小权值,因为在这上面若经过了一个方点,说明可以经过这个点双连通分量中任何一个点并且到达想到的点。(方点所连接的点都是相互可达的)。
所以问题转化为了求树上两点之间路径的最小点权。并且需要注意的是:链顶的点需要把它的父亲节点也考虑进来,因为它的父亲节点与它是属于同一个双连通分量的。感觉圆方树的好处在这里就可以体现出来:即可以通过一个点来反映出整个点双联通分量的情况,并且相连的方点圆点一定是父子关系,由此可以方便的在树上通过一条路径来总结出很多双联通分量的总情况。
所以:树剖+可修改堆可以完美解决。
#include <bits/stdc++.h>
using namespace std;
#define maxn 400000
#define int long long
#define INF 99999999999
int n, m, Q, val[maxn];
int tot, timer, dfn[maxn], low[maxn];
int cnt, fa[maxn], top[maxn], dep[maxn];
int S[maxn], size[maxn], hson[maxn]; struct node
{
int minn;
node () { minn = INF; }
}P[maxn]; struct heap
{
priority_queue <int, vector<int>, greater<int> > q1, q2;
void ins(int x) { q1.push(x); }
void erase(int x) { q2.push(x); }
int top()
{
while(!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop();
return q1.top();
}
}Hp[maxn]; struct edge
{
int cnp = , head[maxn], to[maxn], last[maxn];
void add(int u, int v)
{
to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
}
}E1, E2; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void Tarjan(int u)
{
dfn[u] = low[u] = ++ timer; S[++ S[]] = u;
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i];
if(!dfn[v])
{
Tarjan(v); low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
E2.add(++ tot, u); int x = ;
do
{
x = S[S[] --]; E2.add(tot, x);
}while(x != v);
}
}
else low[u] = min(low[u], dfn[v]);
}
} void dfs(int u, int ff)
{
fa[u] = ff; dep[u] = dep[ff] + ; size[u] = ;
if(u <= n && ff) Hp[ff].ins(val[u]);
for(int i = E2.head[u]; i; i = E2.last[i])
{
int v = E2.to[i]; if(v == ff) continue;
dfs(v, u); size[u] += size[v];
if(size[v] > size[hson[u]]) hson[u] = v;
}
} void dfs2(int u, int gra)
{
dfn[u] = ++ timer; top[u] = gra;
if(hson[u]) dfs2(hson[u], gra);
for(int i = E2.head[u]; i; i = E2.last[i])
{
int v = E2.to[i];
if(v == fa[u] || v == hson[u]) continue;
dfs2(v, v);
}
} void update(int p, int l, int r, int x, int num)
{
if(l == r) { P[p].minn = num; return; }
int mid = (l + r) >> ;
if(x <= mid) update(p << , l, mid, x, num);
else update(p << | , mid + , r, x, num);
P[p].minn = min(P[p << ].minn, P[p << | ].minn);
} int query(int p, int l, int r, int L, int R)
{
if(l > R || r < L) return INF;
if(l >= L && r <= R) return P[p].minn;
int mid = (l + r) >> ;
return min(query(p << , l, mid, L, R), query(p << | , mid + , r, L, R));
} signed main()
{
tot = n = read(), m = read(), Q = read();
for(int i = ; i <= n; i ++) val[i] = read();
for(int i = ; i <= m; i ++)
{
int u = read(), v = read();
E1.add(u, v);
}
for(int i = ; i <= n; i ++)
if(!dfn[i]) Tarjan(i);
timer = ; dfs(, ), dfs2(, );
for(int i = ; i <= n; i ++) update(, , tot, dfn[i], val[i]);
for(int i = n + ; i <= tot; i ++) update(, , tot, dfn[i], Hp[i].top());
while(Q --)
{
char c; cin >> c; int a = read(), b = read();
if(c == 'C')
{
if(fa[a]) Hp[fa[a]].erase(val[a]);
val[a] = b; update(, , tot, dfn[a], val[a]);
if(fa[a]) Hp[fa[a]].ins(val[a]), update(, , tot, dfn[fa[a]], Hp[fa[a]].top());
}
else
{
int u = a, v = b, ans = INF;
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) swap(u, v);
ans = min(ans, query(, , tot, dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if(dep[u] > dep[v]) swap(u, v);
ans = min(ans, query(, , tot, dfn[u], dfn[v]));
if(u > n) ans = min(ans, val[fa[u]]);
printf("%lld\n", ans);
}
}
return ;
}
【题解】【CF Round #278】Tourists的更多相关文章
- UOJ #30. [CF Round #278] Tourists
UOJ #30. [CF Round #278] Tourists 题目大意 : 有一张 \(n\) 个点, \(m\) 条边的无向图,每一个点有一个点权 \(a_i\) ,你需要支持两种操作,第一种 ...
- 圆方树简介(UOJ30:CF Round #278 Tourists)
我写这篇博客的原因 证明我也是学过圆方树的 顺便存存代码 前置技能 双联通分量:点双 然后就没辣 圆方树 建立 新建一个图 定义原图中的所有点为圆点 对于每个点双联通分量(只有两个点的也算) 建立一个 ...
- [CF Round #278] Tourists
给定一个n个点m条边的无向图,求图上的两点的所有的简单路径之间的最小边. 蓝链 $ n,m,q \leq 100000, w_i \leq 10 ^7$ Solution 考虑建立用缩点双来建立广义圆 ...
- 竞赛题解 - CF Round #524 Div.2
CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...
- UOJ30——【CF Round #278】Tourists
1.感谢taorunz老师 2.题目大意:就是给个带权无向图,然后有两种操作, 1是修改某个点的权值 2是询问,询问一个值,就是u到v之间经过点权的最小值(不可以经过重复的点) 操作数,点数,边数都不 ...
- UOJ #30. 【CF Round #278】Tourists
Description Cyberland 有 n 座城市,编号从 1 到 n,有 m 条双向道路连接这些城市.第 j 条路连接城市 aj 和 bj.每天,都有成千上万的游客来到 Cyberland ...
- UOJ #30【CF Round #278】Tourists
求从$ x$走到$ y$的路径上可能经过的最小点权,带修改 UOJ #30 $ Solution:$ 如果两个点经过了某个连通分量,一定可以走到这个连通分量的最小值 直接构建圆方树,圆点存原点的点权 ...
- uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)
- 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...
- CF Round #580(div2)题解报告
CF Round #580(div2)题解报告 T1 T2 水题,不管 T3 构造题,证明大约感性理解一下 我们想既然存在解 \(|a[n + i] - a[i]| = 1\) 这是必须要满足的 既然 ...
随机推荐
- webpack3构建全面提速优化vue-cli
前言 伴随着vue的全球化,各种vue的组件框架越来越完善,从早期的element-ui到vux,iview等越来越多高质量的项目,使用vue进行前端构建已然是一件工程化,模块化,敏捷化的事情 在这其 ...
- 微信小程序 嵌套循环
前言 入门教程之列表渲染多层嵌套循环,目前官方的文档里,主要是一维数组列表渲染的案例,还是比较简单单一,给刚入门的童鞋还是无从入手的感觉. <view wx:for="{{items} ...
- Tomcat+nginx+keepalived+memcached实现双VIP负载均衡及Session会话保持
准备好tomcat 第一台 tar vxf apache-tomcat-7.0.54.tar.gz mv apache-tomcat-7.0.54 /usr/local/tomcat tar vxf ...
- mysql用命令创建用户创建数据库设置权限
1.create database bbs; //创建数据库 2.create user bbs IDENTIFIED by 'bbs'; //创建用户bbs和登录密码bbs 3.grant AL ...
- 4 echo服务器
收到数据,给别人原封不动返回 #4. 将接收到的数据再发送给对方 udpSocket.sendto(recvData[0], recvData[1]) #coding=utf-8 from soc ...
- 使用maven插件生成grpc所需要的Java代码
1.首先需要编写自己需要的.proto文件,本文重点不在这里,.proto可以参考grpc官方例子 https://grpc.io/docs/quickstart/java.html 2.创建自己的J ...
- Bit-map法处理大数据问题
问题引入: 1.给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?2.给定一个千万级别数据量的整数集合,判断哪些是重复元素.3.给 ...
- Android Studio引入AAR文件
一.编译生成AAR文件 二.把AAR文件复制到项目的libs目录下 三.在项目的配置文件中加入如下代码: android { //other code repositories{ flatDir{ d ...
- ACE学习综述(1)
1. ACE学习综述 1.1. ACE项目的优点 可以跨平台使用,基本上可以实现一次编写,多平台运行. ACE本身不仅仅是一个简单的网络框架,对于网络框架涉及到的进程管理.线程管理等系统本身相关的内容 ...
- 在PXC中重新添加掉线节点
Preface When we add a new node into PXC structure,it will estimate the mothed(IST/SST) to tr ...