蓝皮书:异象石 【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) , ...
随机推荐
- canvas高级篇(转载)移动元素
本文转载在http://bbs.blueidea.com/thread-2979405-1-1.html 哈哈哈,好骚气!终于解决了我的需求.可以移动canvas内的多个元素 <!DOCTYPE ...
- SpringBoot+Thyemleaf
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过 ...
- java项目反编译获得源码
经常能找到一些 过时的 项目源码,但是还是有研究价值的.但是肯定是不会给你源码的. 下面介绍怎么反编译: 1.在项目中找到classes这个文件夹,这个就是编译过的文件. 2.下载反编译工具JD-GU ...
- HDU 1028(数字拆分 分治)
题意是求所给的数能够被拆分成的不同组合数目. 方法有三种: 一.完全背包. 限制条件:所用数字不大于 n. 目标:求分解种数(组合出 n 的方法数). 令 dp[ i ][ j ] = x 表示 用前 ...
- C语言memmove()函数: 复制内存内容(可以重叠的内存块)
头文件:#include <string.h> memmove() 用来复制内存内容,其原型为: void * memmove(void *dest, const void *src, s ...
- dubbo的具体使用
dubbo的具体使用: dubbo简介: 1.1. 什么是dubbo 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需一个治理 ...
- flask 文件转为pdf并添加二维码
背景: 宝安区需求,企业会下载表格,打印后填报.填报后收上表格,统一录入PDA.因为某台PDA只能录某个地方的表格,所以他们希望纸质表上有个二维码,扫描出现填报公司的一些信息,以及统计(好像是这样,没 ...
- SSH框架的搭建和测试(Spring + Struts2 + Hibernate)
SSH框架实现了视图.控制器.和模型的彻底分离,同时还实现了业务逻辑层与持久层的分离. Spring实现了MVC中的 Controller的功能,Struts实现Web视图的功能,Hibernate则 ...
- SpringBoot系列: Spring MVC视图方法的补充
SpringMVC 视图方法的参数, 已经在这个文章中写得非常清楚了, 链接为 https://www.cnblogs.com/morethink/p/8028664.html 这篇文章做一些补充. ...
- C# 绘图时使用抗锯齿会多出一个像素
如下图,使用局部绘图覆盖后的效果. 减去像素后效果