题目详见蓝皮书【算法竞赛:进阶指南】。


题目大意:

就是给你一颗树,然后我们要在上面进行三种操作:

 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】的更多相关文章

  1. bzoj2819 DFS序 + LCA + 线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...

  2. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  3. HDU 3966 dfs序+LCA+树状数组

    题目意思很明白: 给你一棵有n个节点的树,对树有下列操作: I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k ...

  4. HDU 6203 ping ping ping(dfs序+LCA+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...

  5. HDU 5296 Annoying problem dfs序 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5296 Description Coco has a tree, w ...

  6. Gym 101142G : Gangsters in Central City(DFS序+LCA+set)

    题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...

  7. POJ 2763 Housewife Wind(DFS序+LCA+树状数组)

    Housewife Wind Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11419   Accepted: 3140 D ...

  8. BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】

    题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...

  9. BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...

随机推荐

  1. Jenkins自动化部署war项目

    基于上一篇Jenkins安装环境,下面对自动打包部署做个备忘 1.安装:Publish over SSH 插件 2.安装完成后,进入下图配置 ↓↓↓ 3.翻到底下↓↓↓ 找到刚刚安装的Publish ...

  2. ruby select 方法,可用于先查询结果后,再次用条件限制

    1. 用于条件过滤 @works=DworkPro.all.order(:work_type) @work_pro=@works.select{ |x| x.job_type == 7} 2. sel ...

  3. jQuery克隆html元素并改变id

    如题,前端操作经常需要ajax异步刷新html页面数据.有时候js里面拼接html代码很麻烦. 因此选择一个div克隆并改变一些值就省了很多事.这个div也可以提前写在html里面hide() 下面是 ...

  4. HDU - 3974 Assign the task (线段树区间修改+构建模型)

    https://cn.vjudge.net/problem/HDU-3974 题意 有一棵树,给一个结点分配任务时,其子树的所有结点都能接受到此任务.有两个操作,C x表示查询x结点此时任务编号,T ...

  5. Mongoose笔记

    Mongoose是在node.js异步环境下对mongodb进行便捷操作的对象模型工具 mongoose是针对mongoDB操作的一个对象模型库,封装了mongoDB对文档的.增删改查等方法 使用Ko ...

  6. Spring boot 工具类静态属性注入及多环境配置

    由于需要访问MongoDB,但是本地开发环境不能直接连接MongoDB,需要通过SecureCRT使用127.0.0.2本地IP代理.但是程序部署到线上生产环境后,是可以直接访问MongoDB的,因此 ...

  7. 判断质数(Java)

    package day01; //输出1-100中质数,并且每十个换行 public class PrimeNum { public static void main(String[] args) { ...

  8. 四十一、Linux 线程——线程同步之条件变量

    41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...

  9. GCC编译器原理(一)------GCC 工具:addr2line、ar、as、c++filt和elfedit

    1.3 GCC 工具 1.3.1 binutils 工具集 工具 描述 addr2line 给出一个可执行文件的内部地址,addr2line 使用文件中的调试信息将地址翻译成源代码文件名和行号. ar ...

  10. 快速学习 javascript

    // js 6种数据类型:字符串.数值.布尔值.undefined.null.object // 三种非数字的数字类型:Infinity -Infinity NaN var str = "H ...