CF487E Tourists[圆方树+树剖(线段树套set)]
做这题的时候有点怂。。基本已经想到正解了。。结果感觉做法有点假,还是看了正解题解。。
首先提到简单路径上经过的点,就想到了一个关于点双的结论:两点间简单路径上所有可能经过的点的并等于路径上所有点所在点双的并,也就是说,在建一棵圆方树,方点表示所在点双里的最小点权,两个圆点之间的路径上所有方点的最小值就是答案。
然后这题有一个修改单点。。修改一个圆点的点权的时候和他相邻的方点维护的min都可能变,所以每个方点开一个multiset维护点双最小值就行了。
但是这样复杂度不能保证,因为每次圆点可能会和一堆方点相连,菊花图的时候就是单次$O(n\log n)$了。。
所以要考虑减少没用的修改。考虑到圆方树是一棵树(废话),对于一个圆点,修改的话,会影响到他的父亲方点和儿子方点。
但是,儿子方点影响不大,如果所有儿子方点的multiset里都不维护这个圆点,每次要查询儿子方点的min只需要和这个圆点合并取min就行了。
所以,每次只要把自己修改一下,把父亲方点对应的multiset修改一下,在树剖的线段树上传一下就行了。
所以,multiset只维护所有儿子圆点。可以结合下图。
如果修改紫色点,那么,对于3路径,lca是一个儿子方点,将其和紫色圆点合并min。。对于2路径,直接跨过紫色圆点了就不管了,对于1号路径,因为所在点双min可能会改掉,所以必须把父亲方点multiset改掉。
然后就随便打个树剖就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=2e5+,INF=0x3f3f3f3f;
struct thxorz{
int head[N],nxt[N<<],to[N<<],tot;
inline void add(int x,int y){
to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
}G1,G2;
char opt[];
int A[N];
int n,m,Q;
#define y G1.to[j]
int dfn[N],low[N],stk[N],top,tim2,cnt;
void tarjan(int x){
dfn[x]=low[x]=++tim2,stk[++top]=x;
for(register int j=G1.head[x];j;j=G1.nxt[j]){
if(!dfn[y]){
tarjan(y),MIN(low[x],low[y]);
if(low[y]==dfn[x]){
int tmp;++cnt;
do tmp=stk[top--],G2.add(cnt,tmp);while(tmp^y);
G2.add(cnt,x);
}
}
else MIN(low[x],dfn[y]);
}
}
#undef y
multiset<int> s[N];
int fa[N],topfa[N],son[N],sum[N],dep[N],pos[N],id[N],tim;
#define y G2.to[j]
void dfs1(int x,int fat){//dbg(x);
fa[x]=fat,dep[x]=dep[fat]+,sum[x]=;int tmp=-;
for(register int j=G2.head[x];j;j=G2.nxt[j])if(y^fat)dfs1(y,x),sum[x]+=sum[y],MAX(tmp,sum[y])&&(son[x]=y);
}
void dfs2(int x,int topf){
topfa[x]=topf,pos[x]=++tim,id[tim]=x;
if(!son[x])return;
dfs2(son[x],topf);
if(x>n){
s[x].insert(A[son[x]]);
for(register int j=G2.head[x];j;j=G2.nxt[j])if(y^fa[x]&&y^son[x])dfs2(y,y),s[x].insert(A[y]);
}
else for(register int j=G2.head[x];j;j=G2.nxt[j])if(y^fa[x]&&y^son[x])dfs2(y,y);
}
#undef y
struct SGT{
int minv[N<<];
#define lc i<<1
#define rc i<<1|1
inline void pushup(int i){minv[i]=_min(minv[lc],minv[rc]);}
void build(int i,int L,int R){
if(L==R){//dbg2(i,id[L]),dbg2(L,R);
if(id[L]>n)minv[i]=*s[id[L]].begin();
else minv[i]=A[id[L]];//dbg(minv[i]);
return;
}
int mid=L+R>>;
build(lc,L,mid),build(rc,mid+,R);pushup(i);
}
int query_min(int i,int L,int R,int ql,int qr){
if(ql<=L&&qr>=R)return minv[i];
int mid=L+R>>,ret=INF;
if(ql<=mid)MIN(ret,query_min(lc,L,mid,ql,qr));
if(qr>mid)MIN(ret,query_min(rc,mid+,R,ql,qr));
return ret;
}
void update(int i,int L,int R,int x,int preval,int val){
if(L==R){
if(id[L]>n)s[id[L]].erase(s[id[L]].find(preval)),s[id[L]].insert(val),minv[i]=*s[id[L]].begin();
else minv[i]=A[id[L]]=val;
return;
}
int mid=L+R>>;
if(x<=mid)update(lc,L,mid,x,preval,val);
else update(rc,mid+,R,x,preval,val);
pushup(i);
}
}T;
inline int ask(int x,int y){
int ret=INF;
while(topfa[x]^topfa[y]){
if(dep[topfa[x]]<dep[topfa[y]])_swap(x,y);
MIN(ret,T.query_min(,,cnt,pos[topfa[x]],pos[x])),x=fa[topfa[x]];
}
if(dep[x]>dep[y])_swap(x,y);
MIN(ret,T.query_min(,,cnt,pos[x],pos[y]));
if(x>n)MIN(ret,A[fa[x]]);
return ret;
}
inline void change(int x,int val){
if(fa[x])T.update(,,cnt,pos[fa[x]],A[x],val);
T.update(,,cnt,pos[x],,val);
} int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
cnt=read(n),read(m),read(Q);
for(register int i=;i<=n;++i)read(A[i]);
for(register int i=,x,y;i<=m;++i)read(x),read(y),G1.add(x,y);
for(register int i=;i<=n;++i)if(!dfn[i])top=,tarjan(i);
dfs1(,),dfs2(,),T.build(,,cnt);
for(register int i=,x,val,y;i<=Q;++i){
scanf("%s",opt);
if(opt[]=='A')read(x),read(y),printf("%d\n",ask(x,y));
else read(x),read(val),change(x,val);
}
return ;
}
总结:这题主要是以减少修改,增加一些合并操作为目标,同时注意要把圆方树是树的性质给用好(就是父亲和儿子的讨论什么的)。。
CF487E Tourists[圆方树+树剖(线段树套set)]的更多相关文章
- CF487E Tourists(圆方树+树链剖分+multiset/可删堆)
CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...
- CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)
QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...
- CF487E Tourists 圆方树、树链剖分
传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...
- Tourists——圆方树
CF487E Tourists 一般图,带修求所有简单路径代价. 简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了. 所以可以圆方树,然后方点维护一下V-DCC内的最小值. 那么, ...
- BZOJ_2238_Mst_树剖+线段树
BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...
- BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树
BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- 【BZOJ5210】最大连通子块和 树剖线段树+动态DP
[BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...
- [LNOI2014]LCA(树剖+线段树)
\(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...
随机推荐
- 【IDEA】格式化代码技巧汇总
1.格式化 Java 代码 快捷键:Ctrl+Alt+L 2.格式化 Mapper 文件中的 SQL 关联到数据库,让 IDEA 认识你的 SQL.如何关联?选择右侧的database,添加数据库即可 ...
- .Net WebApi接口之Swagger集成详解
本文详细的介绍了.net从一个新的项目中创建api后集成swagger调试接口的流程! 1.首先我们创建一个MVC项目(VS2012): 2.然后在项目中的Controllers文件夹中添加API接口 ...
- grafana的metric的计算语句
1.磁盘使用率 .other:((node_filesystem_size_bytes{fstype=~ .my: ((node_filesystem_size_bytes{fstype=~ 2.se ...
- Bootstrap手风琴悬浮下拉框,直接拷~~~
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- POJ 3274/洛谷 1360:Gold Balanced Lineup 黄金阵容平衡
题目描述 Farmer John's N cows (1 ≤ N ≤ 100,000) share many similarities. In fact, FJ has been able to na ...
- Fourier serie
你眼中看似落叶纷飞变化无常的世界,实际只是躺在上帝怀中一份早已谱好的乐章. 时域和频域就像观察一个物体一样,一个是主视图的,一个是侧视图. 1.在有限区间上由任意图形定义的任意函数都可以表示为单纯的正 ...
- 《Brennan's Guide to Inline Assembly》学习笔记
原文见Brennan's Guide to Inline Assembly. AT&T语法 vs Intel语法 DJGPP是基于GCC的,因此它使用AT&T/UNIT语法,这和Int ...
- Oracle 11.2.0.4_Linux单例篇
Linux 下安装Oracle步骤: 1.设置ip地址 2.设置主机名 3.安装oracle依赖的软件包 mkdir /media/cdrom -p mount /dev/cdrom /media ...
- Elasticsearch使用小结之冷热分离
Elasticsearch使用小结之冷热分离 索引迁移 索引setting中的index.routing.allocation.exclude和index.routing.allocation.inc ...
- 剑指offer43:左旋转字符串(字符串):对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。
1 题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”a ...