【CF487E】Tourists(圆方树)
【CF487E】Tourists(圆方树)
题面
题解
首先我们不考虑修改,再来想想这道题目。
我们既然要求的是最小值,那么,在经过一个点双的时候,走的一定是具有较小权值的那一侧。
所以说,我们可以让所有的方点表示它所在的点双的最小权值,
这样子只需要对于圆方树树链剖分之后维护链的最小值就行了。
好的,回归带修改,无非是要动态的维护一下方点的最小权值了。
你问我怎么动态维护若干个值的最小值?搞个\(multiset\)不就好了吗?
但是,现在问题又来了,如果每次修改一个点的权值(这个点当然是圆点啦),
那么,必定会修改所有和它相邻的方点,如果是一个菊花树,然后我们拼命修改根节点,这样子复杂度就起飞了。
现在让我们打开脑洞,大力思考一下怎么办?
我们强行让方点的权值不包括它的父亲(也就是只算它的儿子)
如果求解的时候\(LCA\)是方点,则额外计算一下方点父亲的权值
这样子每个圆点在修改的之后只需要向上修改给父亲方点啦!
于是,我们得到了\(Tarjan\)+圆方树+树链剖分+线段树+\(multiset\)的\(O(nlog^2n)\)的做法啦
(为什么要手写可删堆啊?\(multiset\)不好吗?)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 444444
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Line{int v,next;};
struct Link
{
Line e[MAX<<1];
int h[MAX],cnt;
void Add(int u,int v)
{
e[++cnt]=(Line){v,h[u]};h[u]=cnt++;
e[++cnt]=(Line){u,h[v]};h[v]=cnt++;
}
}Gr,Tr;
multiset<int> MS[MAX];
int W[MAX];
int n,m,Q,Tot;
struct Graph
{
int dfn[MAX],low[MAX],S[MAX],tim,top;
void Tarjan(int u)
{
dfn[u]=low[u]=++tim;S[++top]=u;
for(int i=Gr.h[u];i;i=Gr.e[i].next)
{
int v=Gr.e[i].v;
if(!dfn[v])
{
Tarjan(v);low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
Tr.Add(++Tot,u);int x;
do{x=S[top--];Tr.Add(Tot,x);}while(v!=x);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
}G;
struct SegMentTree
{
int t[MAX<<2];
void Modify(int now,int l,int r,int p,int w)
{
if(l==r){t[now]=w;return;}
int mid=(l+r)>>1;
if(p<=mid)Modify(lson,l,mid,p,w);
else Modify(rson,mid+1,r,p,w);
t[now]=min(t[lson],t[rson]);
}
int Query(int now,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return t[now];
int ret=1e9,mid=(l+r)>>1;
if(L<=mid)ret=min(ret,Query(lson,l,mid,L,R));
if(R>mid)ret=min(ret,Query(rson,mid+1,r,L,R));
return ret;
}
}SMT;
int fa[MAX],tim,dfn[MAX],low[MAX];
int size[MAX],hson[MAX],top[MAX],dep[MAX];
void dfs1(int u,int ff)
{
fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1;
if(u<=n&&ff)MS[ff].insert(W[u]);
for(int i=Tr.h[u];i;i=Tr.e[i].next)
{
int v=Tr.e[i].v;if(v==ff)continue;
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;dfn[u]=++tim;low[tim]=u;
if(hson[u])dfs2(hson[u],tp);
for(int i=Tr.h[u];i;i=Tr.e[i].next)
if(Tr.e[i].v!=fa[u]&&Tr.e[i].v!=hson[u])
dfs2(Tr.e[i].v,Tr.e[i].v);
}
int Query(int u,int v)
{
int ret=1e9;
while(top[u]^top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
ret=min(ret,SMT.Query(1,1,Tot,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
ret=min(ret,SMT.Query(1,1,Tot,dfn[u],dfn[v]));
if(u<=n)return ret;
else return min(ret,W[fa[u]]);
}
void Modify(int u,int w)
{
if(fa[u])
{
MS[fa[u]].erase(MS[fa[u]].find(W[u]));
MS[fa[u]].insert(w);
SMT.Modify(1,1,Tot,dfn[fa[u]],*MS[fa[u]].begin());
}
W[u]=w;SMT.Modify(1,1,Tot,dfn[u],w);
}
int main()
{
Tot=n=read();m=read();Q=read();W[0]=1e9;
for(int i=1;i<=n;++i)W[i]=read();
for(int i=1;i<=m;++i)Gr.Add(read(),read());
G.Tarjan(1);dfs1(1,0);dfs2(1,1);
for(int i=1;i<=n;++i)SMT.Modify(1,1,Tot,dfn[i],W[i]);
for(int i=n+1;i<=Tot;++i)SMT.Modify(1,1,Tot,dfn[i],*MS[i].begin());
char ch[2];
while(Q--)
{
scanf("%s",ch);
int a=read(),b=read();
if(ch[0]=='C')Modify(a,b);
else printf("%d\n",Query(a,b));
}
return 0;
}
【CF487E】Tourists(圆方树)的更多相关文章
- CF487E Tourists(圆方树+树链剖分+multiset/可删堆)
CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...
- CF487E Tourists 圆方树、树链剖分
传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...
- CF487E Tourists[圆方树+树剖(线段树套set)]
做这题的时候有点怂..基本已经想到正解了..结果感觉做法有点假,还是看了正解题解.. 首先提到简单路径上经过的点,就想到了一个关于点双的结论:两点间简单路径上所有可能经过的点的并等于路径上所有点所在点 ...
- CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)
QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...
- Tourists——圆方树
CF487E Tourists 一般图,带修求所有简单路径代价. 简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了. 所以可以圆方树,然后方点维护一下V-DCC内的最小值. 那么, ...
- uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)
- 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...
- CF487E Tourists 【圆方树 + 树剖 + 堆】
题目链接 CF487E 题解 圆方树 + 树剖 裸题 建好圆方树维护路径上最小值即可 方点的值为其儿子的最小值,这个用堆维护 为什么只维护儿子?因为这样修改点的时候就只需要修改其父亲的堆 这样充分利用 ...
- 【学习笔记】圆方树(CF487E Tourists)
终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...
- CF487E Tourists【圆方树+tarjan+multiset+树剖+线段树】
圆方树不仅能解决仙人掌问题(虽然我仙人掌问题也没用过圆方树都是瞎搞过去的),还可以解决一般图的问题 一般图问题在于缩完环不是一棵树,所以就缩点双(包括双向边) 每个方点存他所在点双内除根以外的点的最小 ...
随机推荐
- PS调出春夏外景婚纱照
效果图 先来看看原图和夏季的效果图 先看看原图 教程终于来咯 原图暗部太深,需要将暗部提亮.可以把暗部选区选出来.为了精确选择暗部选区,我利用计算命令如上图所示.最后得到暗部的选区. 上图得到了暗部选 ...
- iOS iCloud云存储数据
https://www.jianshu.com/p/ce8cfaf6030e 2017.11.29 16:05* 字数 452 阅读 302评论 0喜欢 1 因为上一次做了用keychain来持久化存 ...
- Python_动态参数、名称空间、作用域、作用域链、加载顺序、函数的嵌套、global、nonlocal
1.动态参数 当实参数量与形参数量相等时,参数传递正常. def func1(a, b, c): pass func1(1, 2, 3) 当实参数量与形参数量不相等时,则会报错. def func1( ...
- 爬虫——scrapy框架
Scrapy是一个异步处理框架,是纯Python实现的爬虫框架,其架构清晰,模块之间的耦合程度低,可拓展性强,可以灵活完成各种需求.我们只需要定制几个模块就可以轻松实现一个爬虫. 1.架构 Scra ...
- Mysql连接数、线程数、数据包
https://blog.csdn.net/qq_26545305/article/details/79675507
- 【学亮IT手记】mysql创建/查看/切换数据库
--创建数据库 create database web_test1 CHARACTER set utf8; --切换数据库 use web_test1; --查看当前使用的数据库 select DAT ...
- Android——Activity的简绍
Activity Activity的运行机制其实和JavaEE中的servlet很像,而我们的Android系统也就相当与其servlet容器,Activity在其中进行创建实例.初始化.运行.销毁等 ...
- 2017 Python最新面试题及答案16道题
1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...
- python爬虫之初始Selenium
1.初始 Selenium[1] 是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Moz ...
- 深入python的set和dict
一. collections中的abc 和list(Sequence)相似,都继承于Collection,添加了一些方法 二. dict的常见用法 (setdefault,defaultdict,__ ...