做这题的时候有点怂。。基本已经想到正解了。。结果感觉做法有点假,还是看了正解题解。。

首先提到简单路径上经过的点,就想到了一个关于点双的结论:两点间简单路径上所有可能经过的点的并等于路径上所有点所在点双的并,也就是说,在建一棵圆方树,方点表示所在点双里的最小点权,两个圆点之间的路径上所有方点的最小值就是答案。

然后这题有一个修改单点。。修改一个圆点的点权的时候和他相邻的方点维护的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)]的更多相关文章

  1. CF487E Tourists(圆方树+树链剖分+multiset/可删堆)

    CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...

  2. CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)

    QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...

  3. CF487E Tourists 圆方树、树链剖分

    传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...

  4. Tourists——圆方树

    CF487E Tourists 一般图,带修求所有简单路径代价. 简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了. 所以可以圆方树,然后方点维护一下V-DCC内的最小值. 那么, ...

  5. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  6. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  7. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  8. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

  9. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

随机推荐

  1. Odoo13 新变化:存货核算

    Odoo13将于2019年10月发布,本次发布也包含了大量的改进,例如,对存货核算的重构. 去掉了 产品历史价格product.price.history ,增加了 stock valuation l ...

  2. Scala当中什么是RDD(Resilient Distributed Datasets)弹性分布式数据集

    RDD(Resilient Distributed Datasets)弹性分布式数据集.你不好理解的话,可以把RDD就可以看成是一个简单的"动态数组"(比如ArrayList),对 ...

  3. linux下如何查看一个服务所在的安装路径?

    当接手一个不是自己维护的linux服务器,我们常常会想要看看该服务器上是否安装了某个服务,这个服务安装的路径在哪? redis 是开发过程中常常会用到的一个服务,我这里就以这个服务为例,进行说明. 1 ...

  4. 【bitset】Kth Minimum Clique

    #include<bits/stdc++.h> #define B bitset<105> using namespace std; typedef long long ll ...

  5. php 测试php连接redis集群的案例

    <?php$redis_list = ['12.24.18.2:6379'];$client = new RedisCluster(NUll,$redis_list);echo $client- ...

  6. Android opengl 笔记

    1. varying vec2 vTextureCoord; 不能用in vec2 ,varying 表示在vs 和 fs中都可见. 2. android 里面 0 和1 都要打小数点 比如0.0 1 ...

  7. 个人学习HTML以及CSS所得体会

    拥有自己样式的浏览器: 苹果,欧朋,谷歌,IE,火狐 form标签<form></form> 表单属性: 1,action主要同来规定表单的作用,提交到处理器上面处理URL,默 ...

  8. 解决微信小程序Date.parse()获取时间戳IOS显示为NaN

    ios系统不支持2018-03-29这样格式的时间导致出现的这个问题, IOS只识别2018/03/09这样的格式. 上正则 //之前的var data = '2018-03-09 12:00:00' ...

  9. OpenCl入门getting-started-with-opencl-and-gpu-computing

    原文来自于:getting-started-with-opencl-and-gpu-computing/ 对整个程序的注释:http://www.kimicat.com/opencl-1/opencl ...

  10. 解决chrome没有允许添加flash的问题

    有时候测试的时候,需要开启flash 但是Chrome一般都是自己弹出来的 现在弹不出来怎么办 自己添加? chrome://settings/content/flash 对不起  根本没有的 怎么解 ...