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

Luogu

给出一个带点权的无向图,两种操作:

1、修改某点点权。

2、询问x到y之间简单路径能走过的点的最小点权。

题解时间

总感觉是将一堆水题拼出来的丑陋产物(划去)

毫无疑问看题直接搞上圆方树。

用可删堆或者multiset维护方点的权值。

查询直接树剖搞。

但这样会发现修改时间复杂度无法保证。

所以改成每个方点只记录子节点的权值。

当lca为方点时答案计算一下它上面的圆点。

$ O(nlog^{2}n) $

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
typedef long long lint;
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
tar=ret*f;
}
namespace RKK
{
const int N=200011;
struct superheap
{
priority_queue<int> q0,q1;
int size;
int top(){update();return -q0.top();}
void push(int x){q0.push(-x),size++;}
void del(int x){q1.push(-x),size--;}
void update(){while(!q1.empty()){if(q0.top()==q1.top()) q0.pop(),q1.pop();else break;}}
};
int n,nn,m,qaq;
struct segtree
{
int v[N<<2];
void edit(int x,int w,int px=1,int pl=1,int pr=nn)
{
if(pl==pr){v[px]=w;return;}
int pm=pl+pr>>1;
if(x<=pm) edit(x,w,px<<1,pl,pm);
else edit(x,w,px<<1|1,pm+1,pr);
v[px]=min(v[px<<1],v[px<<1|1]);
}
int query(int l,int r,int px=1,int pl=1,int pr=nn)
{
if(l<=pl&&r>=pr) return v[px];
int ret=1145149961;
int pm=pl+pr>>1;
if(l<=pm) ret=min(ret,query(l,r,px<<1,pl,pm));
if(r>pm) ret=min(ret,query(l,r,px<<1|1,pm+1,pr));
return ret;
}
};
struct sumireko{int to,ne;};
int w[N];
int dfn[N],low[N],da;
int sta[N],stp;
int fa[N],dep[N],sz[N],dson[N],top[N],id[N];
superheap heap[N];
segtree sgt;
struct graph
{
sumireko e[N<<1];
int he[N],ecnt;
void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f],he[f]=ecnt;}
void tj(int x,graph *g)
{
dfn[x]=low[x]=++da,sta[++stp]=x;
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)
{
if(!dfn[t])
{
tj(t,g),low[x]=min(low[x],low[t]);
if(low[t]>=dfn[x])
{
nn++;int px=0;
while(px!=t)
{
px=sta[stp--];
g->addline(px,nn),g->addline(nn,px);
}
g->addline(x,nn),g->addline(nn,x);
}
}else low[x]=min(low[x],dfn[t]);
}
}
void dfs(int x)
{
sz[x]=1;
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=fa[x])
{
fa[t]=x,dep[t]=dep[x]+1,dfs(t),sz[x]+=sz[t];
if(x>n) heap[x].push(w[t]);
if(sz[t]>sz[dson[x]]) dson[x]=t;
}
}
void dfs(int x,int tp)
{
if(x>n) w[x]=heap[x].top();
top[x]=tp,id[x]=++da,sgt.edit(id[x],w[x]);
if(dson[x]) dfs(dson[x],tp);
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=fa[x]&&t!=dson[x])
dfs(t,t);
}
}g1,g2;
void getans(int x,int y)
{
int ans=1145149961;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=min(ans,sgt.query(id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=min(ans,sgt.query(id[x],id[y]));
if(x>n) ans=min(ans,w[fa[x]]);
printf("%d\n",ans);
}
char op[5];
int Iris()
{
read(n),read(m),read(qaq),nn=n;
for(int i=1;i<=n;i++) read(w[i]);
for(int i=1,x,y;i<=m;i++) read(x),read(y),g1.addline(x,y),g1.addline(y,x);
g1.tj(1,&g2);
g2.dfs(1),da=0,g2.dfs(1,1);
for(int rkk=1,x,y;rkk<=qaq;rkk++)
{
scanf("%s",op),read(x),read(y);
switch(op[0])
{
case 'A':
getans(x,y);
break;
case 'C':
sgt.edit(id[x],y);
if(fa[x])
{
int px=fa[x];
heap[px].del(w[x]);
heap[px].push(y);
if(heap[px].top()!=w[px])
{
sgt.edit(id[px],heap[px].top());
w[px]=heap[px].top();
}
}
w[x]=y;
break;
}
}
return 0;
}
}
int main(){return RKK::Iris();}

CF487E Tourists(圆方树+树链剖分+multiset/可删堆)的更多相关文章

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

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

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

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

  3. CF487E Tourists[圆方树+树剖(线段树套set)]

    做这题的时候有点怂..基本已经想到正解了..结果感觉做法有点假,还是看了正解题解.. 首先提到简单路径上经过的点,就想到了一个关于点双的结论:两点间简单路径上所有可能经过的点的并等于路径上所有点所在点 ...

  4. uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)

    - 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...

  5. Tourists——圆方树

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

  6. 线段树&数链剖分

    傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...

  7. bzoj4336 骑士的旅行 (树链剖分+multiset)

    首先大概有一个树剖+树套树的做法,但我哪会写啊 然后发现k很小,如果用线段树记每个区间前k大的的话,可以O(k)地合并 而且一个点还有可能有好多个骑士,所以要用multiset维护一下 然后树剖就好啦 ...

  8. CF487E Tourists - Tarjan缩点 + 树剖 + multiset

    Solution 先Tarjan求出点双联通分量 并缩点. 用$multiset$维护 点双内的最小点权. 容易发现, 点双内的最小点权必须包括与它相连的割边的点权. 所以我们必须想办法来维护. 所以 ...

  9. [HNOI2016]网络 [树链剖分,可删除堆]

    考虑在 |不在| 这条链上的所有点上放上一个 \(x\),删除也是,然后用可删除堆就随便草掉了. // powered by c++11 // by Isaunoya #pragma GCC opti ...

随机推荐

  1. opencv笔记-GFTTDetector

    在 "光流跟踪" 中,使用了 Harris 角点作为 LK 光流跟踪输入点.角点定义为在两个方向上均有较大梯度变化的小区域,使用自相关函数描述. 自相关函数为为图像平移前后某一个区 ...

  2. 关于mybatis,需要掌握的基础

    目录 ❀ 总结 mybatis,需要掌握的基础如下: 1.了解ORM 思想.ORM思想的作用.映射配置的两种方式 2.MyBatis开发流程(基本使用) 3.日志框架 4.了解mybatis生命周期并 ...

  3. Vue 源码解读(6)—— 实例方法

    前言 上一篇文章 Vue 源码解读(5)-- 全局 API 详细介绍了 Vue 的各个全局 API 的实现原理,本篇文章将会详细介绍各个实例方法的实现原理. 目标 深入理解以下实例方法的实现原理. v ...

  4. 一个命令让redis服务端所有信息无所遁形~(收藏吃灰系列)

    1.info命令作用 在redis客户端执行INFO 命令以便于计算机解析和人工阅读的简单格式返回有关redis服务端的所有信息和统计数据. 可选参数可用于选择特定的信息部分: Server 服务器基 ...

  5. Kubernetes:更新与回滚

    Blog:博客园 个人 除了创建,Deployment 提供的另一个重要的功能就是更新应用,这是一个比创建复杂很多的过程.想象一下在日常交付中,在线升级是一个很常见的需求,同时应该尽量保证不能因为升级 ...

  6. 如何让测试RFC2544更便捷——RFC2544测试实操

    关键词:RFC2544:吞吐量测试:时延测试:丢包率:背靠背. 作为一名网络测试人员,大家肯定熟知一个测试标准,那就是RFC2544,RFC2544通过提供一个测试网络设备的测试标准,并规定了一系列测 ...

  7. 案例七:shell实现开机自动播放挂载本地yum仓库程序

    shell实现开机自动挂载本地YUM仓库自动化程序,可以在没有网络的情况下也可以使用yum安装程序. #!/bin/bash #自动搭建yum本地仓库 # cdrom () { mount /dev/ ...

  8. win7下安装docker toolbox

    我的笔记本是win10系统,上面安装docker非常简单.只要在官网下载然后一路next就可以了.然而办公室的电脑装的是win7,我也懒得给它换win10.没想到,win7下安装docker这么费劲. ...

  9. MyBatis核心对象

    MyBatis 有三个基本要素: 核心接口和类 MyBatis核心配置文件(mybatis-config.xml) SQL映射文件(mapper.xml) 下面首先介绍 MyBatis 的核心接口和类 ...

  10. omnet++:官方文档翻译总结(四)

    学习翻译自:Adding Statistics Collection - OMNeT++ Technical Articles Part 5 - Adding Statistics Collectio ...