蓝皮书:异象石 【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) , ...
随机推荐
- 阿里云MongoDB存储数据
近期上了个活动,考虑后期的运维及人力成本,还是选择了阿里云的MongoDB,不过阿里云这玩意本地测试官方没有给本地测试链接地址,只能做映射上去了测了... 选了个2核4G的,更多详细信息,可以去阿里上 ...
- Linux记录-配置无密码登录
1.互信的机器都执行 ssh-keygen -t rsa cat ~/.ssh/id_rsa.pub >> /home/hdfs/.ssh/authorized_keys chmod 60 ...
- @JsonFormat的导包问题
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")//注解可以以该格式注入格式@JsonFormat(locale="zh& ...
- bzoj千题计划308:bzoj4589: Hard Nim(倍增FWT+生成函数)
https://www.lydsy.com/JudgeOnline/problem.php?id=4589 n*m*m 做法 dp[i][j] 前i堆石子,异或和为j的方案数 第一重循环可以矩阵快速幂 ...
- c/c++gdb下和发布版本下输出地址不同
相差4字节 相差8个字节 原因: 这4个字节是优化掉了,64位操作系统,函数传参通过寄存器,减少了栈的使用 debug模式下,abc的地址都存下来了.
- windows server 禁用智能卡服务的步骤
许多用户对于系统中的很多功能都不太了解,其中智能卡服务更是少有人知.智能卡服务就是对插入的智能卡进行管理和访问控制,大多数用户都无需使用此项功能.那么在Win7系统中要怎么取消智能卡服务呢? 1.首先 ...
- python3 bytes数据类型探讨
python3中str和bytes分开了,那么bytes与str之间到底是什么关系呢?下面从表现形式.处理方式.存储形式三个方面来阐述其区别 1. 在字符串前面加上b,就表示bytes数据类型 s1 ...
- 细说java系列之泛型
什么是范型 简言之,范型是Java支持在编译期进行类型检查的机制. 这里面包含2层含义:其一,可以使用范型进行类型检查:其二,在编译期进行类型检查. 那么,什么叫做在编译期进行类型检查?可以在运行时进 ...
- 细说log4j之log4j 1.x
官网:http://logging.apache.org/log4j/1.2/manual.html 三大组件:loggers,appenders,layouts. LoggersLogger是一个层 ...
- Java入门系列
包装类 基本数据类型之间的相互转换不是都可以制动转换的,而你强制转换又会出问题,比如String类型的转换为int类型的,那么jdk为了方便用户就提供了相应的包装类. 基本类型对应的包装类 创建一个包 ...