圆方树第二题……

  图中询问的是指定两点之间简单路径上点的最小权值。若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值)。我们可以发现其实就是这两点在圆方树上经过的点的最小权值,因为在这上面若经过了一个方点,说明可以经过这个点双连通分量中任何一个点并且到达想到的点。(方点所连接的点都是相互可达的)。

  所以问题转化为了求树上两点之间路径的最小点权。并且需要注意的是:链顶的点需要把它的父亲节点也考虑进来,因为它的父亲节点与它是属于同一个双连通分量的。感觉圆方树的好处在这里就可以体现出来:即可以通过一个点来反映出整个点双联通分量的情况,并且相连的方点圆点一定是父子关系,由此可以方便的在树上通过一条路径来总结出很多双联通分量的总情况。

  所以:树剖+可修改堆可以完美解决。

#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的更多相关文章

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

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

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

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

  3. [CF Round #278] Tourists

    给定一个n个点m条边的无向图,求图上的两点的所有的简单路径之间的最小边. 蓝链 $ n,m,q \leq 100000, w_i \leq 10 ^7$ Solution 考虑建立用缩点双来建立广义圆 ...

  4. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

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

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

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

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

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

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

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

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

  9. CF Round #580(div2)题解报告

    CF Round #580(div2)题解报告 T1 T2 水题,不管 T3 构造题,证明大约感性理解一下 我们想既然存在解 \(|a[n + i] - a[i]| = 1\) 这是必须要满足的 既然 ...

随机推荐

  1. [BZOJ1076][SCOI2008]奖励关(概率DP)

    Code #include <cstdio> #include <algorithm> #include <cstring> #define N 110 #defi ...

  2. grunt in webstorm

    1.install grunt sudo npm install -g grunt-cli npm install grunt --save-dev

  3. 北京Uber优步司机奖励政策(3月25日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. Altium Designer -- 精心总结

    如需转载请注明出处:http://blog.csdn.NET/qq_29350001/article/details/52199356 以前是使用DXP2004来画图的,后来转行.想来已经有一年半的时 ...

  5. c/c++ 随机数生成

    当程序需要一个随机数时有两种情况下使用: 1.程序中只需使用一次随机数,则调用rand()函数即可 2.程序需要多次使用随机数,那么需要使用srand()函数生成随机数种子在调用rand()函数保证每 ...

  6. 从webview中加载assets中的html文件

    private void readHtmlFormAssets(){ WebSettings webSettings = tipsWebView.getSettings(); webSettings. ...

  7. Python第三方库之openpyxl(3)

    Python第三方库之openpyxl(3) 区域图 区域图类似于折线图,绘图线下面的区域会被填充,通过将分组设置为“standard”.“stacked”或“percentStacked”,可以获得 ...

  8. python基础篇 08 文件操作

    本节主要内容:1. 初识⽂件操作2. 只读(r, rb)3. 只写(w, wb)4. 追加(a, ab)5. r+读写6. w+写读7. a+写读(追加写读)8. 其他操作⽅法9. ⽂件的修改以及另⼀ ...

  9. spring boot 打包问题

    一.jar包 1.maven build package 2.linux 下执行 java -jar & 命令后台运行,也可加入服务运行 二.war包 1.将pom中的<packagin ...

  10. linux备忘录-账号管理与ACL权限设定

    知识 账号管理中的一些文件结构 /etc/passwd 每一行的内容都为下面结构 账号名称:密码:UID:GID:用户信息说明:家目录:shell ---- UID ---- -- 0 -> 代 ...