博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CF487E Tourists 圆方树、树链剖分
阅读量:5364 次
发布时间:2019-06-15

本文共 4801 字,大约阅读时间需要 16 分钟。


注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点

注意:这里不能缩边双联通分量,样例\(2\)就是一个反例

05195a131bfadabfd901034974e15838cd96635b.png

上面这个图如果缩点双会缩成\(3\)个,但是缩边双会将整个图缩成\(1\)个点。

假如我们询问的是\((1,4)\)之间的简单路径,而图中权值最小的点为\(7\)号点,那么如果缩成了边双联通分量,你的答案会是\(7\)号点的权值,意即认为可以走到\(7\)号点,但实际上如果到\(7\)号点,意味着\(5\)号点需要经过\(2\)次,不符合简单路径的要求

所以如果将题意改成“一条边只能经过一次”就是缩边双了

那么我们直接维护圆方树,对于每一个方点使用\(multiset\)维护与它相连的所有圆点的权值,在圆方树上树链剖分计算答案。

当然这样子还是不够的。考虑一种情况:一个圆点连接了一堆方点,然后在这一个圆点上不断进行修改操作,这样每一次修改都会波及一大堆方点的修改,复杂度直接爆炸。

优化:对于所有方点,不去维护它在圆方树上的父亲,那么对于每一次修改,只会波及它在圆方树上的方点父亲。而如果在某一次询问中两点之间的\(LCA\)为方点,还需要额外考虑这个点的父亲的贡献。

#include
#define lch (x << 1)#define rch (x << 1 | 1)#define mid ((l + r) >> 1)#define INF 0x7fffffff//This code is written by Itstusing namespace std;inline int read(){ int a = 0; char c = getchar(); bool f = 0; while(!isdigit(c) && c != EOF){ if(c == '-') f = 1; c = getchar(); } if(c == EOF) exit(0); while(isdigit(c)){ a = a * 10 + c - 48; c = getchar(); } return f ? -a : a;}const int MAXN = 2e5 + 7;struct Edge{ int end , upEd;}Ed[MAXN << 1];int head[MAXN] , val[MAXN] , N , M , Q , cntEd , cnt;int topS , ts , st[MAXN] , dfn[MAXN] , low[MAXN];int ind[MAXN] , rk[MAXN] , fa[MAXN] , dep[MAXN] , son[MAXN] , sz[MAXN] , top[MAXN] , TS;int Tree[MAXN << 2];bool vis[MAXN];vector < int > ch[MAXN];multiset < int > s[MAXN];inline void addEd(int a , int b){ Ed[++cntEd].end = b; Ed[cntEd].upEd = head[a]; head[a] = cntEd;}inline void pop(int t , int bot){ ch[t].push_back(++cnt); do{ ch[cnt].push_back(st[topS]); s[cnt].insert(val[st[topS]]); }while(st[topS--] != bot);}void tarjan(int x , int p){ st[++topS] = x; dfn[x] = low[x] = ++ts; vis[x] = 1; for(int i = head[x] ; i ; i = Ed[i].upEd) if(Ed[i].end != p) if(!vis[Ed[i].end]){ tarjan(Ed[i].end , x); low[x] = min(low[x] , low[Ed[i].end]); if(low[Ed[i].end] >= dfn[x]) pop(x , Ed[i].end); } else low[x] = min(low[x] , dfn[Ed[i].end]);}void dfs1(int x , int p){ fa[x] = p; dep[x] = dep[p] + 1; sz[x] = 1; for(int i = 0 ; i < ch[x].size() ; ++i){ dfs1(ch[x][i] , x); sz[x] += sz[ch[x][i]]; if(sz[son[x]] < sz[ch[x][i]]) son[x] = ch[x][i]; }}void dfs2(int x , int t){ ind[x] = ++TS; rk[TS] = x; top[x] = t; if(!son[x]) return; dfs2(son[x] , t); for(int i = 0 ; i < ch[x].size() ; ++i) if(ch[x][i] != son[x]) dfs2(ch[x][i] , ch[x][i]);}inline void pushup(int x){ Tree[x] = min(Tree[lch] , Tree[rch]);}void init(int x , int l , int r){ if(l == r) Tree[x] = rk[l] <= N ? val[rk[l]] : *s[rk[l]].begin(); else{ init(lch , l , mid); init(rch , mid + 1 , r); pushup(x); }}void modify(int x , int l , int r , int tar , int num){ if(l == r) Tree[x] = num; else{ if(mid >= tar) modify(lch , l , mid , tar , num); else modify(rch , mid + 1 , r , tar , num); pushup(x); }}int query(int x , int l , int r , int L , int R){ if(l >= L && r <= R) return Tree[x]; int minN = INF; if(mid >= L) minN = min(minN , query(lch , l , mid , L , R)); if(mid < R) minN = min(minN , query(rch , mid + 1 , r , L , R)); return minN;}int work(int x , int y){ int tx = top[x] , ty = top[y] , minN = INF; while(tx != ty){ if(dep[tx] < dep[ty]){ swap(x , y); swap(tx , ty); } minN = min(minN , query(1 , 1 , cnt , ind[tx] , ind[x])); x = fa[tx]; tx = top[x]; } if(dep[x] > dep[y]) swap(x , y); minN = min(minN , query(1 , 1 , cnt , ind[x] , ind[y])); if(x > N) minN = min(minN , val[fa[x]]); return minN;}inline char getc(){ char c = getchar(); while(!isupper(c)) c = getchar(); return c;}int main(){#ifndef ONLINE_JUDGE freopen("in","r",stdin); //freopen("out","w",stdout);#endif cnt = N = read(); M = read(); Q = read(); for(int i = 1 ; i <= N ; ++i) val[i] = read(); for(int i = 1 ; i <= M ; ++i){ int a = read() , b = read(); addEd(a , b); addEd(b , a); } tarjan(1 , 0); dfs1(1 , 0); dfs2(1 , 1); init(1 , 1 , cnt); while(Q--) if(getc() == 'A') printf("%d\n" , work(read() , read())); else{ int a = read() , b = read(); if(a != 1){ s[fa[a]].erase(s[fa[a]].find(val[a])); s[fa[a]].insert(b); modify(1 , 1 , cnt , ind[fa[a]] , *s[fa[a]].begin()); } val[a] = b; modify(1 , 1 , cnt , ind[a] , b); } return 0;}

转载于:https://www.cnblogs.com/Itst/p/10289571.html

你可能感兴趣的文章
【洛谷】【堆+模拟】P2278 操作系统
查看>>
hdu3307 欧拉函数
查看>>
Spring Bean InitializingBean和DisposableBean实例
查看>>
[容斥][dp][快速幂] Jzoj P5862 孤独
查看>>
Java基础之字符串匹配大全
查看>>
面向对象
查看>>
lintcode83- Single Number II- midium
查看>>
[工具] Sublime Text 使用指南
查看>>
Web服务器的原理
查看>>
#10015 灯泡(无向图连通性+二分)
查看>>
HAL层三类函数及其作用
查看>>
web@h,c小总结
查看>>
Data Structure 基本概念
查看>>
NEYC 2017 游记
查看>>
[搬运] 写给 C# 开发人员的函数式编程
查看>>
Python之旅Day14 JQuery部分
查看>>
core--线程池
查看>>
他山之石:加载图片的一个小问题
查看>>
shell - 常识
查看>>
Spring Cloud Stream消费失败后的处理策略(三):使用DLQ队列(RabbitMQ)
查看>>