UOJ30——【CF Round #278】Tourists
1、感谢taorunz老师
2、题目大意:就是给个带权无向图,然后有两种操作,
1是修改某个点的权值
2是询问,询问一个值,就是u到v之间经过点权的最小值(不可以经过重复的点)
操作数,点数,边数都不超过100000
3、分析:首先看这道题,就感觉用双联通+树剖搞一搞可以过,可是怎么搞呢
首先双联通是必然的了,可是正常的缩点+树剖会爆零随便试试就知道了
然后我们需要不正常的缩点,我们在正常的缩点后加入割点,割点向它所属的一切双联通分量连边
这样,我们就不怕询问的u和v中有割点了,可是虽然询问是logn*logn了,但是修改会超时,于是我们想想应该怎么搞呢
taorunz告诉我说,图会满足一个性质,块的父亲是割点,割点的父亲是块,我们维护块的值是,
这个块所代表的双联通,除了它父亲的那个割点,那么我们这么修改,如果修改的非割点,就正常修改,
如果是割点,那么它的父亲这个块也要修改,这样修改就是o(logn)了,我们就可以过了,但是树剖的询问中
如果lca是块,我们还要询问这个块的父亲,这样,这道题就完美的AC了,(各种bug
</pre><pre name="code" class="cpp">#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
struct node{
int from, to, next;
} G[2000010];
struct segment_tree{
int q[50000010];
int x, y;
inline void init(){
for(int i = 1; i <= 4500000; i ++) q[i] = 2147483647;
return;
}
inline void add(int l, int r, int o){
if(l == r && l == x){
q[o] = y;
return;
}
int mid = (l + r) / 2;
if(x <= mid) add(l, mid, 2 * o);
if(x > mid) add(mid + 1, r, 2 * o + 1);
q[o] = q[2 * o];
if(q[2 * o + 1] < q[o]) q[o] = q[2 * o + 1];
return;
}
inline int query(int l, int r, int o){
if(x <= l && r <= y){
return q[o];
}
int mid = (l + r) / 2;
int ret = 2147483647;
if(x <= mid){
int wl = query(l, mid, 2 * o);
if(wl < ret) ret = wl;
}
if(y > mid){
int wl = query(mid + 1, r, 2 * o + 1);
if(wl < ret) ret = wl;
}
return ret;
}
} qzh, mmd;
struct tree_chain_paritition{
int Top[2000010];
int Size[2000010];
int Height[2000010];
int Father[2000010];
int Num[2000010];
int value[2000010];
node G[2000010];
int head[2000010], ff, de, n;
int vis[2000010];
int is_cut[2000010];
inline void for_tree(){
for(int i = 1; i <= n; i ++) is_cut[i] = 1;
}
inline void init(){
memset(is_cut, 0, sizeof(is_cut));
memset(head, -1, sizeof(head));
de = 0;
}
inline void insert(int u, int v){
//printf("%d %d\n", u, v);
ff ++;
G[ff] = (node){u, v, head[u]};
head[u] = ff;
return;
}
inline void dfs1(int u, int fa, int k){
Father[u] = fa;
Height[u] = k;
Size[u] = 1;
vis[u] = 1;
for(int i = head[u]; i != -1; i = G[i].next){
node e = G[i];
if(!vis[e.to]){
dfs1(e.to, u, k + 1);
Size[u] += Size[e.to];
}
}
return;
}
inline void dfs2(int u, int fa){
vis[u] = 1;
int o = 0, pos;
for(int i = head[u]; i != -1; i = G[i].next){
node e = G[i];
if(!vis[e.to]){
if(Size[e.to] > o){
pos = i;
o = Size[e.to];
}
}
}
if(o != 0){
node e = G[pos];
qzh.x = ++ de;
qzh.y = value[e.to];
qzh.add(1, n, 1);
Top[e.to] = Top[u];
Num[e.to] = de;
dfs2(e.to, u);
}
for(int i = head[u]; i != -1; i = G[i].next){
node e = G[i];
if(!vis[e.to] && i != pos){
qzh.x = ++ de;
qzh.y = value[e.to];
qzh.add(1, n, 1);
Top[e.to] = e.to;
Num[e.to] = de;
dfs2(e.to, u);
}
}
return;
}
inline void solve(){
qzh.x = ++ de;
qzh.y = value[1];
qzh.add(1, n, 1);
Top[1] = 1;
Num[1] = de;
memset(vis, 0, sizeof(vis));
dfs2(1, 0);
return;
}
inline void change(int s, int t){
qzh.x = Num[s];
qzh.y = t;
qzh.add(1, n, 1);
return;
}
inline int qmin(int s, int t){
int ret = 2147483647;
while(Top[s] != Top[t]){
if(Height[Top[s]] > Height[Top[t]]) swap(s, t);
qzh.x = Num[Top[t]];
qzh.y = Num[t];
int wl = qzh.query(1, n, 1);
if(wl < ret) ret = wl;
t = Father[Top[t]];
}
if(Height[s] > Height[t]) swap(s, t);
qzh.x = Num[s];
qzh.y = Num[t];
int wl = qzh.query(1, n, 1);
if(wl < ret) ret = wl;
if(!is_cut[s] && s != 1){
qzh.x = Num[Father[s]];
qzh.y = Num[Father[s]];
wl = qzh.query(1, n, 1);
if(wl < ret) ret = wl;
}
return ret;
}
inline void debug(){
printf("\nNum:");
for(int i = 1; i <= n; i ++) printf("%d ", Num[i]);
printf("\nSize:");
for(int i = 1; i <= n; i ++) printf("%d ", Size[i]);
printf("\nHeight:");
for(int i = 1; i <= n; i ++) printf("%d ", Height[i]);
printf("\nTop:");
for(int i = 1; i <= n; i ++) printf("%d ", Top[i]);
printf("\n");
}
} wt;
int first[2000010], Next[2000010], poss[2000010], Left[2000010], Right[2000010];
int labccno[2000010];
int ff;
int w[2000010];
int head[2000010], next[2000010];
int pre[2000010], iscut[2000010], bccno[2000010], use_times[2000010];
int head1[2000010], next1[2000010], kt[2000010];
int vis[2000010];
int dfs_clock, bcc_cnt;
int dark;
int he[2000010], ne[2000010];
int poss_fa[2000010];
stack<node> S;
inline int dfs(int u, int fa);
inline void insert(int u, int v);
int main(){
int n, m, q;
while(scanf("%d%d%d", &n, &m, &q) != EOF){
memset(head, -1, sizeof(head));
memset(first, -1, sizeof(first));
memset(head1, -1, sizeof(head1));
memset(iscut, 0, sizeof(iscut));
memset(he, -1, sizeof(he));
for(int i = 1; i <= n; i ++){
scanf("%d", &w[i]);
}
for(int i = 1; i <= m; i ++){
int u, v;
scanf("%d%d", &u, &v);
insert(u, v);
insert(v, u);
}
dfs_clock = bcc_cnt = 0;
for(int i = 1; i <= n; i ++){
if(!pre[i]) int wl = dfs(i, -1);
}
for(int i = 1; i <= n; i ++) labccno[i] = bccno[i];
/*for(int i = 1; i <= n; i ++){
printf("%d ", bccno[i]);
}
printf("\n");*/
for(int i = 1; i <= n; i ++){
if(iscut[i]){
bcc_cnt ++;
bccno[i] = bcc_cnt;
}
}
qzh.init();
wt.init();
wt.n = bcc_cnt;
for(int i = 1; i <= bcc_cnt; i ++) wt.value[i] = 2147483647;
for(int i = 1; i <= n; i ++){
wt.value[bccno[i]] = min(wt.value[bccno[i]], w[i]);
}
memset(vis, 0, sizeof(vis));
/*for(int i = 1; i <= n; i ++){
printf("%d ", bccno[i]);
}
printf("\n");*/
for(int i = 1; i <= n; i ++){
if(iscut[i]){
for(int j = head1[i]; j != -1; j = next1[j]){
wt.insert(bccno[i], kt[j]);
wt.insert(kt[j], bccno[i]);
//wt.value[kt[j]] = min(wt.value[kt[j]], w[i]);
}
}
else{
for(int j = head[i]; j != -1; j = G[j].next){
int ii = bccno[i], jj = bccno[G[j].to];
if(ii != jj){
wt.insert(ii, jj);
wt.insert(jj, ii);
}
}
}
}
memset(wt.vis, 0, sizeof(wt.vis));
wt.dfs1(1, 0, 1);
int N = n;
for(int i = 1; i <= n; i ++) if(iscut[i]){
N ++;
ne[i] = he[wt.Father[bccno[i]]];
he[wt.Father[bccno[i]]] = i;
wt.is_cut[bccno[i]] = 1;
wt.value[wt.Father[bccno[i]]] = min(wt.value[wt.Father[bccno[i]]], w[i]);
}
wt.solve();
mmd.init();
int yy = 0;
for(int i = 1; i <= n; i ++){
Next[i] = first[bccno[i]];
first[bccno[i]] = i;
}
for(int i = 1; i <= bcc_cnt; i ++){
Left[i] = yy + 1;
for(int j = first[i]; j != -1; j = Next[j]){
++ yy;
mmd.x = yy;
mmd.y = w[j];
mmd.add(1, N, 1);
poss[j] = yy;
}
for(int j = he[i]; j != -1; j = ne[j]){
++ yy;
mmd.x = yy;
mmd.y = w[j];
mmd.add(1, N, 1);
poss_fa[j] = yy;
}
Right[i] = yy;
}
/*for(int i = 1; i <= n; i ++){
printf("%d ", bccno[i]);
}
printf("\n");*/
//if(m < n) wt.for_tree();
// wt.debug();
for(int i = 1; i <= q; i ++){
char str[5];
int u, v;
scanf("%s%d%d", str, &u, &v);
if(str[0] == 'C'){
w[u] = v;
mmd.x = poss[u];
mmd.y = v;
mmd.add(1, N, 1);
mmd.x = Left[bccno[u]];
mmd.y = Right[bccno[u]];
int st = mmd.query(1, N, 1);
wt.change(bccno[u], st);
if(iscut[u]){
mmd.x = poss_fa[u];
mmd.y = v;
mmd.add(1, N, 1);
mmd.x = Left[wt.Father[bccno[u]]];
mmd.y = Right[wt.Father[bccno[u]]];
int st = mmd.query(1, N, 1);
wt.change(wt.Father[bccno[u]], st);
}
}
else{
if(u == v) printf("%d\n", w[u]);
else printf("%d\n", wt.qmin(bccno[u], bccno[v]));
}
}
}
return 0;
}
inline void insert(int u, int v){
ff ++;
G[ff] = (node){u, v, head[u]};
head[u] = ff;
return;
}
inline int dfs(int u, int fa){
int lowu = pre[u] = ++ dfs_clock;
int child = 0;
for(int i = head[u]; i != -1; i = G[i].next){
node e = G[i];
if(!pre[e.to]){
S.push(e);
child ++;
int lowv = dfs(e.to, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u]){
iscut[u] = true;
bcc_cnt ++;
for(; ; ){
node h = S.top(); S.pop();
if(bccno[h.from] != bcc_cnt) {
next1[++ dark] = head1[h.from];
head1[h.from] = dark;
kt[dark] = bcc_cnt;
bccno[h.from] = bcc_cnt;
use_times[h.from] ++;
}
if(bccno[h.to] != bcc_cnt){
next1[++ dark] = head1[h.to];
head1[h.to] = dark;
kt[dark] = bcc_cnt;
bccno[h.to] = bcc_cnt;
use_times[h.to] ++;
}
if(h.from == u && h.to == e.to){
break;
}
}
}
}
else if(pre[e.to] < pre[u] && e.to != fa){
S.push(e);
lowu = min(lowu, pre[e.to]);
}
}
if(fa < 0 && child == 1) iscut[u] = 0;
return lowu;
}
UOJ30——【CF Round #278】Tourists的更多相关文章
- uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)
- 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...
- 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:$ 如果两个点经过了某个连通分量,一定可以走到这个连通分量的最小值 直接构建圆方树,圆点存原点的点权 ...
- 【题解】【CF Round #278】Tourists
圆方树第二题…… 图中询问的是指定两点之间简单路径上点的最小权值.若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值).我们可以发现其实就是这两点 ...
- 圆方树简介(UOJ30:CF Round #278 Tourists)
我写这篇博客的原因 证明我也是学过圆方树的 顺便存存代码 前置技能 双联通分量:点双 然后就没辣 圆方树 建立 新建一个图 定义原图中的所有点为圆点 对于每个点双联通分量(只有两个点的也算) 建立一个 ...
- UOJ #30. [CF Round #278] Tourists
UOJ #30. [CF Round #278] Tourists 题目大意 : 有一张 \(n\) 个点, \(m\) 条边的无向图,每一个点有一个点权 \(a_i\) ,你需要支持两种操作,第一种 ...
- 【CS round 34】Minimize Max Diff
[题目链接]:https://csacademy.com/contest/round-34/task/minimize-max-diff/ [题意] 给你n个数字; 数组按顺序不下降; 让你删掉k个数 ...
- 【CS Round 34】Max Or Subarray
[题目链接]:https://csacademy.com/contest/round-34/summary/ [题意] 让你找一个最短的连续子串; 使得这个子串里面所有数字or起来最大; [题解] 对 ...
- 【CF Round 434 B. Which floor?】
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
随机推荐
- mysql常用命令之-用户密码修改
--创建用户 CREATE USER 'user1'@'localhost' IDENTIFIED BY 'pass1'; GRANT SELECT,INSERT,UPDATE,DELETE ON * ...
- 任务二:1、选择器 2、连接集中状态的顺序 3、浮动的用发和原理 4、盒模型在IE和Google等不同浏览器的区别与联系
1.选择器类型 标签选择器,类选择器,ID选择器,组合选择器,伪类和伪元素,属性选择器,子选择器,同胞选择器, :not()选择器 1.同胞选择器 相邻同胞标签: h2 + p{ color:red; ...
- C#读写文本和连接数据库
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- IBatis一对多查询
public class User { public int UserId { get; set; } public string UserName { get; set; } } public cl ...
- JQuery------判断拥有某个class或id的div是否存在
if ($(".Btn,#Show").length > 0) { alert("存在"); } else { alert("不存在" ...
- 使用mybatis-generator自动生成model、dao、mapping文件
参考文献:http://www.cnblogs.com/smileberry/p/4145872.html 一.所需库 1.mybatis-generator库 2.连接DB的驱动(此以mysql为例 ...
- ansible执行playbook时间显示的python脚本
import datetime import os import time from ansible.plugins.callback import CallbackBase class Callba ...
- thinkphp 语言包丢失
Thinkphp 语言包丢失 造成的原因有那些 1.复制模板 预览时内容出现英文状态 如:show.html 解决:找到lang ,在zh-cn 复制想对应的文件包 改下名称就有可以 如:admin_ ...
- AOP PostSharp
using System; using System.Collections.Generic; using System.Linq; using System.Text; using PostShar ...
- centos 7.0 安装
最小化安装的 主要查看硬盘使用时间 需要安装 smartmontools 这个 [root@localhost ~]# yum install -y smartmontools 已加载插件:fast ...