「HEOI2014」大工程
问题分析
首先不难想到是虚树。建完虚树需要保持节点间原先的距离关系。
然后总距离和最小距离用树形DP求,最大距离用两遍dfs即可。注意统计的时候只对关键点进行统计。
真是麻烦
参考程序
ac的时候是loj上速度最后一页,代码第四长的……
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 1000010;
const long long INF = 1000000000010;
const int MaxLog = 20;
struct edge {
int To, Next;
long long Length;
edge() : To( 0 ), Next( 0 ), Length( 0LL ) {}
edge( int _To, int _Next, long long _Length ) :
To( _To ), Next( _Next ), Length( _Length ) {}
};
int n, q, k, A[ Maxn ], Important[ Maxn ];
int DFa[ Maxn ][ MaxLog ], Deep[ Maxn ], Dfn[ Maxn ], Time;
int Stack[ Maxn ];
int Flag[ Maxn ];
struct graph {
int Start[ Maxn ], Used, State;
edge Edge[ Maxn << 1 ];
graph() {}
inline void Init( int _DYT ) {
State = _DYT;
Used = 0;
return;
}
inline void AddDirectedEdge( int x, int y, long long Len ) {
if( Flag[ x ] != State ) {
Flag[ x ] = State;
Start[ x ] = 0;
}
Edge[ ++Used ] = edge( y, Start[ x ], Len );
Start[ x ] = Used;
return;
}
inline void AddUndirectedEdge( int x, int y, long long Len ) {
AddDirectedEdge( x, y, Len );
AddDirectedEdge( y, x, Len );
return;
}
};
graph Prime, Now;
long long Ans, Max, Min;
int Size[ Maxn ], Id;
void Build( int u, int Fa ) {
Deep[ u ] = Deep[ Fa ] + 1;
Dfn[ u ] = ++Time;
DFa[ u ][ 0 ] = Fa;
for( int i = 1; i < MaxLog; ++i )
DFa[ u ][ i ] = DFa[ DFa[ u ][ i - 1 ] ][ i - 1 ];
for( int t = Prime.Start[ u ]; t; t = Prime.Edge[ t ].Next ) {
int v = Prime.Edge[ t ].To;
if( v == Fa ) continue;
Build( v, u );
}
return;
}
inline bool Cmp( int x, int y ) {
return Dfn[ x ] < Dfn[ y ];
}
int GetLca( int x, int y ) {
if( Deep[ x ] < Deep[ y ] ) swap( x, y );
for( int i = MaxLog - 1; i >= 0; --i )
if( Deep[ DFa[ x ][ i ] ] >= Deep[ y ] )
x = DFa[ x ][ i ];
if( x == y ) return x;
for( int i = MaxLog - 1; i >= 0; --i )
if( DFa[ x ][ i ] != DFa[ y ][ i ] ) {
x = DFa[ x ][ i ];
y = DFa[ y ][ i ];
}
return DFa[ x ][ 0 ];
}
struct info {
long long Min, Sec;
info() : Min( INF ), Sec( INF ) {}
info( long long _Min, long long _Sec ) : Min( _Min ), Sec( _Sec ) {}
inline info operator + ( const long long Other ) const {
return info( Min + Other, Sec + Other );
}
inline info operator + ( const info Other ) const {
return ( Min < Other.Min ) ? info( Min, min( Sec, Other.Min ) ) : info( Other.Min, min( Min, Other.Sec ) ) ;
}
};
info GetMin( int u, int Fa ) {
info Ans = info( INF, INF );
if( Important[ u ] == Now.State ) Ans.Min = 0;
for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
int v = Now.Edge[ t ].To;
if( v == Fa ) continue;
Ans = Ans + ( GetMin( v, u ) + Now.Edge[ t ].Length );
}
Min = min( Min, Ans.Min + Ans.Sec );
return Ans;
}
void GetMax( int u, int Fa, long long Len ) {
if( Len > Max && Important[ u ] == Now.State ) {
Max = Len;
Id = u;
}
for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
int v = Now.Edge[ t ].To;
if( v == Fa ) continue;
GetMax( v, u, Len + Now.Edge[ t ].Length );
}
return;
}
long long GetAns( int u, int Fa ) {
Size[ u ] = 0; long long Sum = 0;
if( Important[ u ] == Now.State ) Size[ u ] = 1;
for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
int v = Now.Edge[ t ].To;
if( v == Fa ) continue;
long long SS = GetAns( v, u );
Ans += Sum * Size[ v ] + Size[ u ] * ( Now.Edge[ t ].Length * Size[ v ] + SS );
Sum += SS + Now.Edge[ t ].Length * Size[ v ];
Size[ u ] += Size[ v ];
}
return Sum;
}
void Work( int Case ) {
Now.Init( Case );
scanf( "%d", &k );
for( int i = 1; i <= k; ++i ) scanf( "%d", &A[ i ] );
for( int i = 1; i <= k; ++i ) Important[ A[ i ] ] = Case;
sort( A + 1, A + k + 1, Cmp );
Stack[ 0 ] = 1; Stack[ 1 ] = 1;
int Len, Lca;
for( int i = 1; i <= k; ++i ) {
if( i == 1 && A[ 1 ] == 1 ) continue;
if( i > 1 && A[ i ] == A[ i - 1 ] ) continue;
Lca = GetLca( Stack[ Stack[ 0 ] ], A[ i ] );
if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] ] ] )
Stack[ ++Stack[ 0 ] ] = A[ i ];
else {
while( Deep[ Stack[ Stack[ 0 ] - 1 ] ] > Deep[ Lca ] ) {
Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
Now.AddUndirectedEdge( Stack[ Stack[ 0 ] - 1 ], Stack[ Stack[ 0 ] ], Len );
--Stack[ 0 ];
}
if( Deep[ Stack[ Stack[ 0 ] - 1 ] ] == Deep[ Lca ] ) {
Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
Now.AddUndirectedEdge( Stack[ Stack[ 0 ] - 1 ], Stack[ Stack[ 0 ] ], Len );
--Stack[ 0 ];
Stack[ ++Stack[ 0 ] ] = A[ i ];
} else {
Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Lca ];
Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Lca, Len );
--Stack[ 0 ];
Stack[ ++Stack[ 0 ] ] = Lca;
Stack[ ++Stack[ 0 ] ] = A[ i ];
}
}
}
while( Stack[ 0 ] > 1 ) {
Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ], Len );
--Stack[ 0 ];
}
Min = INF;
GetMin( 1, 0 );
Max = -1;
GetMax( A[ 1 ], 0, 0 );
Max = -1;
GetMax( Id, 0, 0 );
Ans = 0;
GetAns( 1, 0 );
printf( "%lld %lld %lld\n", Ans, Min, Max );
return;
}
int main() {
scanf( "%d", &n );
for( int i = 1; i < n; ++i ) {
int x, y;
scanf( "%d%d", &x, &y );
Prime.AddUndirectedEdge( x, y, 1 );
}
Build( 1, 0 );
scanf( "%d", &q );
for( int i = 1; i <= q; ++i ) Work( i );
return 0;
}
「HEOI2014」大工程的更多相关文章
- 「ZJOI2016」大森林 解题报告
「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...
- LOJ#2230. 「BJOI2014」大融合
LOJ#2230. 「BJOI2014」大融合 题目描述 小强要在$N$个孤立的星球上建立起一套通信系统.这套通信系统就是连接$N$个点的一个树.这个树的边是一条一条添加上去的. 在某个时刻,一条边的 ...
- 【HEOI2014】大工程<虚树>
虚树 我们每天都用心思索着,这究竟是为了什么呢?我想我也不知道,只是觉得如果人不思考问题就很无聊. 我觉得虚树不是什么数据结构,就是一种技巧或者工具.它能把树中\(k\)个关键点以\(O(klogk) ...
- 【BZOJ】【3611】【HEOI2014】大工程
虚树+树形DP 本题100W的点数……不用虚树真的好吗…… Orz ZYF 我的感悟: dp的过程跟SPOJ 1825 FTOUR2 的做法类似,依次枚举每个子树,从当前子树和之前的部分中各找一条最长 ...
- 「HEOI2014」南园满地堆轻絮
题目链接 戳我 题目出处 菩萨蛮·南园满地堆轻絮 温庭筠 南园满地堆轻絮,愁闻一霎清明雨.雨后却斜阳,杏花零落香 ...
- @loj - 2092@ 「ZJOI2016」大森林
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...
- 【LOJ】#2230. 「BJOI2014」大融合
题解 我现在真是太特么老年了 一写数据结构就颓废,难受 这题就是用lct维护子树 ???lct怎么维护子树 这样想,我们给每个点记录虚边所在的子树大小,只发生在Access和link的时候 这样的话我 ...
- loj2230 「BJOI2014」大融合
LCT裸题 我LCT学傻了这题明显可以树剖我不会树剖了 本来的siz是Splay上的子树和,并没有什么用. 所以每个点维护虚子树和和子树和 虚子树和即虚边连接的子树和,且只有在access和link操 ...
- loj2092 「ZJOI2016」大森林
ref不是太懂-- #include <algorithm> #include <iostream> #include <cstring> #include < ...
随机推荐
- Lua的API函数
1. 基础库 我们在整个教程中使用了各种主题下的基本库. 下表提供了相关页面的链接,并列出了本Lua教程各部分所涵盖的功能. 编号 库/方法 作用 1 错误处理 包括错误处理函数,如断言, 错误,如L ...
- ZOOKEEPER之WATCHER简介
zookeeper通过watcher机制,可以实现数据的修改,删除等情况的监听 可以设置观察的操作:exists,getChildren,getData 可以触发观察的操作:create,delete ...
- C#面向对象11 里氏转换
里氏转换 1.子类可以赋值给父类. using System; using System.Collections.Generic; using System.Linq; using System.Te ...
- 在Global.asax中 注册Application_Error事件 捕获全局异常
参考于:https://shiyousan.com/post/635813858052755170 在ASP.NET MVC中,通过应用程序生命周期中的Application_Error事件可以捕获到 ...
- 异常-Throwable的几个常见方法
package cn.itcast_04; import java.text.ParseException; import java.text.SimpleDateFormat; import jav ...
- 谷歌浏览器禁用JS步骤
前奏: 当你想访问一个页面,因为不符合访问条件,而被JS阻拦:或者你打开的页面特效太多,干扰视线:亦或者JS的某个功能禁止了你的某些行为: 是不是很难受, 好办,咱给他禁了不就好啦,大胆地屏蔽它,不管 ...
- 仍然有人在叫喊C语言已经过时了
现在,仍然有人在叫喊C语言已经过时了.还有什么值得学习的?看看现在使用Python.PHP和其他语言有多简单.谁去学旧的C语言?是真的吗?作者下载了这两种语言的底层源代码.由于空间的限制,它没有分析框 ...
- Centos搭建hexo教程
hexo文档:https://hexo.io/zh-cn/ 1.安装Git # sudo yum install git-core// 查看版本# git version// 输出git versio ...
- JVM类加载机制和内存模型
一.JVM类加载机制 首先需要了解一下类加载器(ClassLoader): ClassLoader是Java的一个核心组件,它主要作用是从系统外部获得Class二进制数据流,然后将数据流装载到系统,交 ...
- 关于STM32运行时程序卡在B.处的解决方法
文章转载自:https://blog.csdn.net/u014470361/article/details/78780444 背景: 程序运行时,发现程序卡死在B.处. 解决方法: 程序卡死在B.处 ...