给定一个n个点m条边的无向图,求图上的两点的所有的简单路径之间的最小边。

蓝链

$ n,m,q \leq 100000, w_i \leq 10 ^7$

Solution

考虑建立用缩点双来建立广义圆方树,然后方点的值是当前点双内最小的点 ,这样就直接维护树上的最小值就可以了。 但如果更新的是根节点。那么他的每个方儿子都会被更新。所以特别处理一下根节点即可。记方点权值为除根节点外的点。特别处理一下即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s)
typedef long long LL;
typedef long double LD;
const int BUF_SIZE = (int)1e6 + 10;
struct fastIO {
char buf[BUF_SIZE], buf1[BUF_SIZE];
int cur, cur1;
FILE *in, *out;
fastIO() {
cur = BUF_SIZE, in = stdin, out = stdout;
cur1 = 0;
}
inline char getchar() {
if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0;
return *(buf + (cur++));
}
inline void putchar(char ch) {
*(buf1 + (cur1++)) = ch;
if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0;
}
inline int flush() {
if (cur1 > 0) fwrite(buf1, cur1, 1, out);
return cur1 = 0;
}
}IO;
#define getchar IO.getchar
#define putchar IO.putchar
int read() {
char ch = getchar();
int x = 0, flag = 1;
for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
return x * flag;
}
void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar(x % 10 + 48);
}
void putString(char s[], char EndChar = '\n') {
rep(i, 0, strlen(s) - 1) putchar(*(s + i));
if(~EndChar) putchar(EndChar);
} #define Maxn 300009
struct edge {
int to, nxt;
}g[Maxn << 1], g1[Maxn << 1];
int n, m, head[Maxn], e, e1, head1[Maxn];
multiset<int> S[Maxn];
int val[Maxn];
int dfn[Maxn], low[Maxn], _clk, cnt_Squ;
stack <int> s;
int top[Maxn], dep[Maxn], size[Maxn], son[Maxn];
int fa[Maxn], efn[Maxn], _index;
namespace INIT {
void add(int u, int v) {
g[++e] = (edge){v, head[u]}, head[u] = e;
}
void add1(int u, int v) {
g1[++e1] = (edge){v, head1[u]}, head1[u] = e1;
}
void tarjan(int u, int fa) {
dfn[u] = low[u] = ++_clk;
s.push(u);
for(int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if(v != fa)
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
add1(n + (++cnt_Squ), u), add1(u, n + cnt_Squ);
int a;
do {
a = s.top(); s.pop();
add1(n + cnt_Squ, a), add1(a, n + cnt_Squ);
}while(a != v);
}
}else low[u] = min(low[u], dfn[v]);
}
}
void dfs_init(int u, int f) {
size[u] = 1;
dep[u] = dep[f] + 1, fa[u] = f;
for(int i = head1[u]; ~i; i = g1[i].nxt) {
int v = g1[i].to;
if(v != f) {
dfs_init(v, u);
size[u] += size[v];
if(son[u] == -1 || size[son[u]] < size[v]) v = son[u];
}
}
}
void dfs_link(int u, int _top) {
top[u] = _top;
dfn[u] = ++_index, efn[_index] = u;
if(~son[u]) dfs_link(son[u], _top);
for(int i = head1[u]; ~i; i = g1[i].nxt) {
int v = g1[i].to;
if(v ^ fa[u] && v ^ son[u]) dfs_link(v, v);
}
}
void Main() {
clar(head, -1);
clar(head1, -1);
n = read(), m = read();
rep(i, 1, n) val[i] = read();
rep(i, 1, m) {
int u = read(), v = read();
add(u, v), add(v, u);
}
tarjan(1, 0);
clar(dfn, 0), _clk = 0;
clar(son, -1);
dfs_init(1, 0);
dfs_link(1, 1);
rep(i, 2, n) S[fa[i] - n].insert(val[i]);
}
}
namespace SGMT_tree {
int tree[Maxn << 2];
#define lc(x) ((x) << 1)
#define rc(x) ((x) << 1 | 1)
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r
void pushup(int root) {
tree[root] = min(tree[lc(root)], tree[rc(root)]);
}
void build(int rt, int l, int r) {
if(l == r) {
tree[rt] = (efn[l] <= n) ? (val[efn[l]]) : (*S[efn[l] - n].begin());
return ;
}
int mid = (l + r) >> 1;
build(ls), build(rs);
pushup(rt);
}
void modify(int rt, int l, int r, int pos) {
if(l == r) {
tree[rt] = (efn[l] <= n) ? (val[efn[l]]) : (*S[efn[l] - n].begin());
return;
}
int mid = (l + r) >> 1;
(pos <= mid) ? modify(ls, pos) : modify(rs, pos);
pushup(rt);
}
int query(int rt, int l, int r, int x, int y) {
if(x <= l && r <= y) return tree[rt];
int mid = (l + r) >> 1;
if(mid >= y) return query(ls, x, y);
if(mid + 1 <= x) return query(rs, x, y);
return min(query(ls, x, y), query(rs, x, y));
}
#undef lc
#undef rc
#undef ls
#undef rs
}
namespace SOLVE {
void Main() {
int amt = cnt_Squ + n;
SGMT_tree :: build(1, 1, amt);
rep(i, 1, read()) {
char s = getchar();
int x = read(), y = read();
if(s == 'C') {
if(x > 1) {
S[fa[x] - n].erase(S[fa[x] - n].lower_bound(val[x]));
S[fa[x] - n].insert(y);
SGMT_tree :: modify(1, 1, amt, dfn[fa[x]]);
}
val[x] = y;
SGMT_tree :: modify(1, 1, amt, dfn[x]);
}
if(s == 'Q') {
int Tmp = x, res = INT_MAX;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res = min(res, SGMT_tree :: query(1, 1, amt, dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
res = min(res, SGMT_tree :: query(1, 1, amt, dfn[x], dfn[y]));
if(x > n) res = min(res, val[fa[x]]);
assert(res != INT_MAX);
write(val[Tmp] - res), putchar('\n');
}
}
}
}
int main() {
INIT :: Main();
SOLVE :: Main();
#ifdef Qrsikno
debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
return IO.flush();
}

[CF Round #278] Tourists的更多相关文章

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

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

  2. 圆方树简介(UOJ30:CF Round #278 Tourists)

    我写这篇博客的原因 证明我也是学过圆方树的 顺便存存代码 前置技能 双联通分量:点双 然后就没辣 圆方树 建立 新建一个图 定义原图中的所有点为圆点 对于每个点双联通分量(只有两个点的也算) 建立一个 ...

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

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

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

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

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

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

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

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

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

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

  8. CF Round #551 (Div. 2) D

    CF Round #551 (Div. 2) D 链接 https://codeforces.com/contest/1153/problem/D 思路 不考虑赋值和贪心,考虑排名. 设\(dp_i\ ...

  9. CF Round #510 (Div. 2)

    前言:没想到那么快就打了第二场,题目难度比CF Round #509 (Div. 2)这场要难些,不过我依旧菜,这场更是被\(D\)题卡了,最后\(C\)题都来不及敲了..最后才\(A\)了\(3\) ...

随机推荐

  1. [开源]OSharpNS - .net core 快速开发框架 - 简介

    什么是OSharp OSharpNS全称OSharp Framework with .NetStandard2.0,是一个基于.NetStandard2.0开发的一个.NetCore快速开发框架.这个 ...

  2. 转: java DES的算法片码

    转自: https://www.zhihu.com/question/36767829 作者:郭无心链接:https://www.zhihu.com/question/36767829/answer/ ...

  3. CentOS LAMP一键安装网站环境及添加域名

    一般的VPS用户普遍使用一键安装包和WEB管理面板居多,在一键安装包中,使用LAMP和LNMP的普遍居多. 第一个版本的LAMP环境包安装过程以及建站过程分享出来. 第一.LAMP一键包环境的安装 目 ...

  4. The 2014 ACM-ICPC Asia Mudanjiang Regional Contest 【部分题解】

    2014牡丹江亚洲区域赛邀请赛 B题:图论题目 题解:这里 K题:想法题 分析:两种变化.加入和交换.首先:星号是n的话最少须要的数字是n+1,那么能够首先推断数字够不够,不够的话如今最前面添数字,假 ...

  5. 【Mongodb教程 第一课 补加课1 】windows7 下安装mongodb 开启关闭服务

    mongodb在2.2版本开始就不支持windows xp了(我想现在用xp的应该也是带着情怀的一部分人吧,我只是一个工匠而已),windows下server8 R2,64位,32位,只是32位只支持 ...

  6. Android NDK编程浅入深出之--Android.mk

        Android.mk Android.mk是一个向Android NDK构建系统描写叙述NDK项目的GUN Makefile片段.它是每个NDK项目的必备组件. 构建系统希望它出如今jni子文 ...

  7. ffmpeg转码本地文件(一)

    ffmpeg转码本地文件(一) 实现目标:输入本地文件.实现本地文件转码,里面包括mux层转码,codec层转码,视频格式转换,音频重採样等功能,功能点请看凝视.注意:凝视非常重要. #ifndef ...

  8. css3动画入门transition、animation

    css3动画 transition.animation CSS3 transition demo <!DOCTYPE html> <html> <head> < ...

  9. Redhat enterpise6 安装unix2dos/dos2unix

    初用unix2dos,在rhel6 上 用yum install unix2dos , 提示源不可用, 那好吧, 就去rpm包网:http://rpm.pbone.net/ 下载了一个unix2dos ...

  10. 检查 统计 异常 通信 time_wait

    [root@hadoop1 conf]# netstat -n | grep -v 127.0.0.1 | grep -v :3306  | grep TIME_WAIT | sort -k 5n | ...