蓝皮书:异象石 【dfs序+lca】
题目详见蓝皮书【算法竞赛:进阶指南】。
题目大意:
就是给你一颗树,然后我们要在上面进行三种操作:
1.标记某个点 或者 2.撤销某个点的标记 以及 3.询问标记点在树上连通所需的最短总边权
数据范围:
点数以及操作数:1e5,边权:1e9(意思就是答案要 long long 存)。
分析:
这道题比赛的时候看的是真懵逼。。。
表示只会 n^3 做法(最多会n^2),以及特殊形态(比如链或者菊花图)的骗分法。
然鹅正解大概是 $O(n log n)$ 的做法,和树搭上了关系,加上这数据范围...
于是正解真是这个复杂度。(看到标程的时候表示惊讶,我太弱了)
标算就是用的dfs序加上lca的算法(如题)
首先我们不考虑 2、3 操作,我们先考虑如果树上有 k 个点被标记了,我们要得到树上 k 个点连通图的最小总边权。
我们可以在纸上画出这棵树以及标记的点,然后我们从左到右把点连成一块。
这时我们发现每两个相邻的点之间(相当于dfs序)的距离加上最后一个点和第一个点的距离,和正好是答案的两倍。
也就是说,如果把这些标记点按照dfs序排成一列,首尾相连形成一个环的话,答案就是这个环相邻点距离之和除以二。
(这种东西考场上怎么做得出来嘛)
那么我们回到原题,如果用上面的方法暴力处理答案,那么复杂度是 $O(n^{2} log n)$ 的(还不如 我自己想到的 n^2 咧)。
那么我们结合加点删点特殊的性质,以此优化算法复杂度。
我们发现加点其实就是在原环两相邻点之间插入了一个新点,然后原来两个相邻点的贡献没了,但是多了新点与这两个点分别的贡献。
那么删点类似的,就是令原环中某个点与相邻的两个点之间的贡献删除,并且多了这两个点之间的距离的贡献。
于是我们就可以用一个set来维护标记点,然后每次求距离的时候要用到 lca。
(lca建议常数小的树剖,倍增效率感人,tarjan 的话比较冷门基本不考虑)
那么我们就可以愉快地抄敲代码了!
代码 :
- //by Judge
- #include<bits/stdc++.h>
- #pragma GCC optimize(2)
- #define It set<int>::iterator
- #define ll long long
- using namespace std;
- const int M=1e5+;
- #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
- char buf[<<],*p1,*p2;
- inline int read(){ int x=;
- char c=getchar(); while(!isdigit(c)) c=getchar();
- for(;isdigit(c);c=getchar()) x=x*+c-''; return x;
- } inline int cread(){ char c=getchar();
- while(c!='+'&&c!='-'&&c!='?') c=getchar();
- return c=='?'?:(c=='+'?:);
- } char sr[<<],z[];int C=-,Z;
- inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
- inline void print(ll x,char chr='\n'){
- if(C><<)Ot(); while(z[++Z]=x%+,x/=);
- while(sr[++C]=z[Z],--Z);sr[++C]=chr;
- } int n,m,pat,tim,head[M],f[M],son[M]; ll ans,dis[M];
- int siz[M],top[M],dep[M],dfn[M],p[M]; set<int> s;
- struct Edge{ int to,val,nxt;
- Edge(int v,int c,int x):to(v),val(c),nxt(x){} Edge(){}
- }e[M<<];
- inline void add(int u,int v,int c){
- e[++pat]=Edge(v,c,head[u]),head[u]=pat;
- e[++pat]=Edge(u,c,head[v]),head[v]=pat;
- }
- #define v e[i].to
- void dfs(int u,int fa){
- siz[u]=,f[u]=fa,dep[u]=dep[fa]+;
- for(int i=head[u];i;i=e[i].nxt) if(v^fa){
- dis[v]=dis[u]+e[i].val,
- dfs(v,u),siz[u]+=siz[v];
- if(siz[v]>siz[son[u]]) son[u]=v;
- }
- } void dfs(int u){
- dfn[u]=++tim,p[tim]=u;
- if(!top[u]) top[u]=u; if(!son[u]) return ;
- top[son[u]]=top[u],dfs(son[u]);
- for(int i=head[u];i;i=e[i].nxt)
- if(v^f[u]&&v^son[u]) dfs(v);
- }
- #undef v
- inline int lca(int u,int v){
- while(top[u]^top[v])
- (dep[top[u]]>dep[top[v]])?
- u=f[top[u]]:v=f[top[v]];
- return dep[u]<dep[v]?u:v;
- } inline ll get(int u,int v){
- return dis[u]+dis[v]-dis[lca(u,v)]*;
- } inline It L(It it){
- return (it==s.begin())?--s.end():--it;
- } inline It R(It it){
- return (it==--s.end())?s.begin():++it;
- }
- int main(){
- n=read();
- for(int i=,u,v,c;i<n;++i)
- u=read(),v=read(),
- c=read(),add(u,v,c);
- dfs(,),dfs(),m=read();
- for(int opt,x,t;m;--m){
- opt=cread(); It it;
- if(opt==) print(ans/);
- else if(opt==){ x=read();
- if(s.size()){
- it=s.lower_bound(dfn[x]);
- if(it==s.end()) it=s.begin(); t=*L(it);
- ans+=get(x,p[t])+get(x,p[*it])-get(p[t],p[*it]);
- } s.insert(dfn[x]);
- } else if(opt==){ x=read();
- if(s.size()>){
- it=s.find(dfn[x]),t=*L(it),it=R(it);
- ans-=get(x,p[t])+get(x,p[*it])-get(p[t],p[*it]);
- } s.erase(dfn[x]);
- }
- } return Ot(),;
- }
蓝皮书:异象石 【dfs序+lca】的更多相关文章
- bzoj2819 DFS序 + LCA + 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...
- BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 3127 Solved: 795[Submit][Status][Discu ...
- HDU 3966 dfs序+LCA+树状数组
题目意思很明白: 给你一棵有n个节点的树,对树有下列操作: I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k ...
- HDU 6203 ping ping ping(dfs序+LCA+树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...
- HDU 5296 Annoying problem dfs序 lca
Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5296 Description Coco has a tree, w ...
- Gym 101142G : Gangsters in Central City(DFS序+LCA+set)
题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...
- POJ 2763 Housewife Wind(DFS序+LCA+树状数组)
Housewife Wind Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 11419 Accepted: 3140 D ...
- BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】
题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...
- BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...
随机推荐
- zk创建集群
在单机环境下和创建集群. 需要注意的点: 配置数据文件myid 1/2/3 对应server.1/2/3 通过./zkCli.sh -server [ip]:[port] 检测集群是否创建成功 在z ...
- C#设计模式(9)——代理模式
1.代理模式介绍 在软件开发中有时会遇到不能直接使用对象的问题,如我们要使用的对象在进程外,甚至在远程的机器上,但是我们要使用这个对象的功能怎么办呢?代理模式就可以用来解决这个问题.举一个生活中的例子 ...
- 微服务之consul
一.概述 consul是google开源的一个使用go语言开发的服务发现.配置管理中心服务.内置了服务注册与发现框 架.分布一致性协议实现.健康检查.Key/Value存储.多数据中心方案,不再需要依 ...
- Linux下Maven私服Nexus3.x环境构建操作记录【转】
Maven介绍Apache Maven是一个创新的软件项目管理和综合工具.Maven提供了一个基于项目对象模型(POM)文件的新概念来管理项目的构建,可以从一个中心资料片管理项目构建,报告和文件.Ma ...
- linux 精简开机自启动
centos7 精简开机自启动 ntsysv rsyslog crond sshd network
- 【1】【leetcode-115】 不同的子序列 distinct-subsequences
不同的子序列 distinct-subsequences(hard) (忘了,典型) 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删 ...
- 一.ArrayList原理及实现学习总结
一.ArrayList介绍 ArrayList是一种线性数据结构,它的底层是用数组实现的,相当于动态数组.与Java中的数组相比,它的容量能动态增长.类似于C语言中的动态申请内存,动态增长内存. 当创 ...
- Java动态代理 深度详解
代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常 ...
- C# web IIS服务器 DateTime 带中文解决
C# Web应用在某些电脑IIS上部署运行,读取当前时间带有中文,比如2018-5-1 星期一 上午 12:00:00,虽然使用Format转换可以解决,但代码量较大难免遗漏,会引发问题,为了解决该问 ...
- 通过修改配置文件修改MySQL的时区设置
一.找到my.ini文件 二.将时区改为东八区 添加:default-time-zone='+08:00'