LOJ#2339 通道
题意:给你三棵树,求所有点对在三棵树上的距离和中的最大值。
解:首先有个暴力,然后还有个迭代乱搞,可以得到61分...
namespace bf {
inline void solve() {
for(int i = ; i <= n; i++) {
for(int j = i; j <= n; j++) {
Ans = std::max(Ans, t1.dis(i, j) + t2.dis(i, j) + t3.dis(i, j));
}
}
printf("%lld\n", Ans);
return;
}
} namespace naive {
inline void Rand() {
int x = rand() % n + ;
for(int T = ; T <= ; T++) {
int y = ;
LL large = -INF;
for(int i = ; i <= n; i++) {
LL temp = t1.dis(x, i) + t2.dis(x, i) + t3.dis(x, i);
if(temp > large) {
large = temp;
y = i;
}
}
x = y;
Ans = std::max(Ans, large);
}
return;
}
inline void solve() {
for(int i = ; i <= ; i++) {
Rand();
}
printf("%lld\n", Ans);
return;
}
}
61分代码
有个部分分是只有两棵树。
我们在第一棵树上枚举lca,那么就相当于把这些点全部挂到第二棵树上,边权是深度。此时可以用直径的性质来维护最远点对。
#define forson(t, x, i) for(int i = t.e[x], y = t.edge[i].v; i; i = t.edge[i].nex, y = t.edge[i].v) inline bool check_same() {
std::vector<uLL> v, u;
for(int x = ; x <= n; x++) {
v.clear(), u.clear();
forson(t2, x, i) {
v.push_back(t2.edge[i].len * N + y);
}
forson(t3, x, i) {
u.push_back(t3.edge[i].len * N + y);
}
int len = v.size();
if(len != u.size()) return false;
std::sort(v.begin(), v.end());
std::sort(u.begin(), u.end());
for(int i = ; i < len; i++) {
if(v[i] != u[i]) return false;
}
}
return true;
} namespace same {
Data data[N];
inline LL exdis(const int &x, const int &y) {
return * t2.dis(x, y) + t1.d[x] + t1.d[y];
}
inline void merge(Data &x, const Data &y, const LL &v) {
int xa = x.a, xb = x.b, ya = y.a, yb = y.b;
LL d12 = exdis(xa, xb), d34 = exdis(ya, yb);
LL d13 = exdis(xa, ya), d14 = exdis(xa, yb);
LL d23 = exdis(xb, ya), d24 = exdis(xb, yb);
if(d34 > d12) {
d12 = d34;
x = y;
}
if(d13 > d12) {
d12 = d13;
x.a = xa;
x.b = ya;
}
if(d14 > d12) {
d12 = d14;
x.a = xa;
x.b = yb;
}
if(d23 > d12) {
d12 = d23;
x.a = xb;
x.b = ya;
}
if(d24 > d12) {
d12 = d24;
x.a = xb;
x.b = yb;
}
Ans = std::max(Ans, std::max(std::max(d13, d14), std::max(d23, d24)) - v);
return;
}
void DFS(int x, int f) {
data[x] = Data(x, x);
forson(t1, x, i) {
if(y == f) continue;
DFS(y, x);
merge(data[x], data[y], t1.d[x] << );
}
return;
}
inline void solve() {
DFS(, );
return;
}
}
46分代码
正解:这不还有一棵树吗?根据暴力写挂和情报中心的经验,我们边分治 + 虚树,即可去掉第一棵树的限制。把边分治的两部分染成不同颜色。
在第二棵树上建虚树,第三棵树上维护两种颜色的直径。
答案就用不同颜色不同集合的来更新。合并的时候每种颜色分开合并。
/**
* There is no end though there is a start in space. ---Infinity.
* It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
* Only the person who was wisdom can read the most foolish one from the history.
* The fish that lives in the sea doesn't know the world in the land.
* It also ruins and goes if they have wisdom.
* It is funnier that man exceeds the speed of light than fish start living in the land.
* It can be said that this is an final ultimatum from the god to the people who can fight.
*
* Steins;Gate
*/ #include <bits/stdc++.h> typedef long long LL;
typedef unsigned long long uLL;
const int N = ;
const LL INF = 4e18; struct Edge {
int nex, v;
LL len;
bool vis;
}edge[N << ], EDGE[N << ]; int tp = , TP; struct Data {
int a, b;
LL v;
Data(int A = , int B = , LL V = ) {
a = A;
b = B;
v = V;
}
}data1[N], data2[N]; int pw[N << ], n, rdP[N], e[N], siz[N], Cnt, _n, small, root, use[N], Time, vis[N], E[N], K, imp[N], RT, col[N];
LL Ans, d[N]; struct Tree {
Edge edge[N << ]; int tp = ;
int e[N], pos2[N], num2, ST[N << ][], deep[N];
LL d[N];
inline void add(int x, int y, LL z) {
edge[++tp].v = y;
edge[tp].len = z;
edge[tp].nex = e[x];
e[x] = tp;
return;
}
void DFS_1(int x, int f) {
pos2[x] = ++num2;
ST[num2][] = x;
deep[x] = deep[f] + ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) continue;
d[y] = d[x] + edge[i].len;
DFS_1(y, x);
ST[++num2][] = x;
}
return;
}
inline void prework() {
for(int j = ; j <= pw[num2]; j++) {
for(int i = ; i + ( << j) - <= num2; i++) {
if(deep[ST[i][j - ]] < deep[ST[i + ( << (j - ))][j - ]]) {
ST[i][j] = ST[i][j - ];
}
else {
ST[i][j] = ST[i + ( << (j - ))][j - ];
}
}
}
return;
}
inline int lca(int x, int y) {
x = pos2[x];
y = pos2[y];
if(x > y) std::swap(x, y);
int t = pw[y - x + ];
if(deep[ST[x][t]] < deep[ST[y - ( << t) + ][t]]) {
return ST[x][t];
}
else {
return ST[y - ( << t) + ][t];
}
}
inline LL dis(int x, int y) {
if(!x || !y) {
return -INF;
}
return d[x] + d[y] - (d[lca(x, y)] << );
}
inline void work() {
LL z;
for(int i = , x, y; i < n; i++) {
scanf("%d%d%lld", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
DFS_1(, );
prework();
return;
}
#undef add
}t1, t2, t3; namespace bf {
inline void solve() {
for(int i = ; i <= n; i++) {
for(int j = i; j <= n; j++) {
Ans = std::max(Ans, t1.dis(i, j) + t2.dis(i, j) + t3.dis(i, j));
}
}
return;
}
} namespace naive {
inline void Rand() {
int x = rand() % n + ;
for(int T = ; T <= ; T++) {
int y = ;
LL large = -INF;
for(int a = ; a <= n; a++) {
int i = rdP[a];
LL temp = t1.dis(x, i) + t2.dis(x, i) + t3.dis(x, i);
if(temp > large) {
large = temp;
y = i;
}
}
x = y;
Ans = std::max(Ans, large);
}
return;
}
inline void solve() {
for(int i = ; i <= ; i++) {
Rand();
}
return;
}
} namespace fire {
inline void Rand() {
int x = rand() % n + ;
for(int T = ; T <= ; T++) {
int y = ;
LL large = -INF;
for(int a = ; a <= n; a++) {
int i = rdP[a];
LL temp = t1.dis(x, i) + t2.dis(x, i) + t3.dis(x, i);
if(temp > large) {
large = temp;
y = i;
}
else if(rand() % < T) {
large = temp;
y = i;
}
}
x = y;
Ans = std::max(Ans, large);
}
return;
}
inline void solve() {
for(int i = ; i <= ; i++) {
Rand();
}
return;
}
} #define forson(t, x, i) for(int i = t.e[x], y = t.edge[i].v; i; i = t.edge[i].nex, y = t.edge[i].v) inline bool check_same() {
std::vector<uLL> v, u;
for(int x = ; x <= n; x++) {
v.clear(), u.clear();
forson(t2, x, i) {
v.push_back(t2.edge[i].len * N + y);
}
forson(t3, x, i) {
u.push_back(t3.edge[i].len * N + y);
}
int len = v.size();
if(len != u.size()) return false;
std::sort(v.begin(), v.end());
std::sort(u.begin(), u.end());
for(int i = ; i < len; i++) {
if(v[i] != u[i]) return false;
}
}
return true;
} namespace same {
Data data[N];
inline LL exdis(const int &x, const int &y) {
return * t2.dis(x, y) + t1.d[x] + t1.d[y];
}
inline void merge(Data &x, const Data &y, const LL &v) {
int xa = x.a, xb = x.b, ya = y.a, yb = y.b;
LL d12 = exdis(xa, xb), d34 = exdis(ya, yb);
LL d13 = exdis(xa, ya), d14 = exdis(xa, yb);
LL d23 = exdis(xb, ya), d24 = exdis(xb, yb);
if(d34 > d12) {
d12 = d34;
x = y;
}
if(d13 > d12) {
d12 = d13;
x.a = xa;
x.b = ya;
}
if(d14 > d12) {
d12 = d14;
x.a = xa;
x.b = yb;
}
if(d23 > d12) {
d12 = d23;
x.a = xb;
x.b = ya;
}
if(d24 > d12) {
d12 = d24;
x.a = xb;
x.b = yb;
}
Ans = std::max(Ans, std::max(std::max(d13, d14), std::max(d23, d24)) - v);
return;
}
void DFS(int x, int f) {
data[x] = Data(x, x);
forson(t1, x, i) {
if(y == f) continue;
DFS(y, x);
merge(data[x], data[y], t1.d[x] << );
}
return;
}
inline void solve() {
DFS(, );
return;
}
} #undef forson inline void add(int x, int y, LL z) {
edge[++tp].v = y;
edge[tp].len = z;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline void ADD(int x, int y) {
EDGE[++TP].v = y;
EDGE[TP].nex = E[x];
E[x] = TP;
return;
} void rebuild(int x, int f) {
int temp = ;
for(int i = t1.e[x]; i; i = t1.edge[i].nex) {
int y = t1.edge[i].v;
LL len = t1.edge[i].len;
if(y == f) continue;
if(!temp) {
add(x, y, len);
add(y, x, len);
temp = x;
}
else if(!t1.edge[i].nex) {
add(temp, y, len);
add(y, temp, len);
}
else {
add(temp, ++Cnt, );
add(Cnt, temp, );
temp = Cnt;
add(temp, y, len);
add(y, temp, len);
}
rebuild(y, x);
}
return;
} void getroot(int x, int f) {
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || edge[i].vis) continue;
getroot(y, x);
siz[x] += siz[y];
if(std::max(siz[y], _n - siz[y]) < small) {
small = std::max(siz[y], _n - siz[y]);
root = i;
}
}
return;
} inline void work(int x) {
if(use[x] == Time) return;
use[x] = Time;
E[x] = col[x] = ;
return;
} void DFS_1(int x, int f, int flag) {
siz[x] = ;
if(x <= n) {
work(x);
imp[++K] = x;
col[x] = flag;
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || edge[i].vis) continue;
d[y] = d[x] + edge[i].len;
DFS_1(y, x, flag);
siz[x] += siz[y];
}
return;
} inline bool cmp(const int &a, const int &b) {
return t2.pos2[a] < t2.pos2[b];
} inline void build_t() {
static int stk[N], top;
std::sort(imp + , imp + K + , cmp);
K = std::unique(imp + , imp + K + ) - imp - ;
stk[top = ] = imp[];
for(int i = ; i <= K; i++) {
int x = imp[i], y = t2.lca(x, stk[top]);
work(y);
while(top > && t2.pos2[y] <= t2.pos2[stk[top - ]]) {
ADD(stk[top - ], stk[top]);
top--;
}
if(stk[top] != y) {
ADD(y, stk[top]);
stk[top] = y;
}
stk[++top] = x;
}
while(top > ) {
ADD(stk[top - ], stk[top]);
top--;
}
RT = stk[top];
return;
} inline bool operator < (const Data &a, const Data &b) {
return a.v < b.v;
} inline LL exdis(int x, int y) {
return t3.dis(x, y) + d[x] + d[y] + t2.d[x] + t2.d[y];
} inline void merge(Data &x, const Data &y) {
int xa = x.a, xb = x.b, ya = y.a, yb = y.b;
LL d12 = exdis(xa, xb), d34 = exdis(ya, yb);
LL d13 = exdis(xa, ya), d14 = exdis(xa, yb);
LL d23 = exdis(xb, ya), d24 = exdis(xb, yb);
if(d34 > d12) {
d12 = d34;
x = y;
}
if(d13 > d12) {
d12 = d13;
x.a = xa;
x.b = ya;
}
if(d14 > d12) {
d12 = d14;
x.a = xa;
x.b = yb;
}
if(d23 > d12) {
d12 = d23;
x.a = xb;
x.b = ya;
}
if(d24 > d12) {
x.a = xb;
x.b = yb;
}
return;
} inline void merge(int x, int y, LL v) {
int p1 = data1[x].a, p2 = data1[x].b, p3 = data2[x].a, p4 = data2[x].b;
int p5 = data1[y].a, p6 = data1[y].b, p7 = data2[y].a, p8 = data2[y].b;
/// cal ans
Ans = std::max(Ans, std::max(std::max(exdis(p1, p7), exdis(p1, p8)), std::max(exdis(p2, p7), exdis(p2, p8))) + v);
Ans = std::max(Ans, std::max(std::max(exdis(p3, p5), exdis(p3, p6)), std::max(exdis(p4, p5), exdis(p4, p6))) + v);
/// update data1[x] data2[x]
merge(data1[x], data1[y]);
merge(data2[x], data2[y]);
return;
} void DFS_2(int x, LL v) {
data1[x] = data2[x] = Data(, );
if(col[x] == ) {
data1[x] = Data(x, x);
}
else if(col[x] == ) {
data2[x] = Data(x, x);
}
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
DFS_2(y, v);
merge(x, y, v - (t2.d[x] << ));
}
return;
} void e_div(int x) {
if(_n == ) {
return;
}
small = N;
getroot(x, );
edge[root].vis = edge[root ^ ].vis = ;
x = edge[root].v;
int y = edge[root ^ ].v; ++Time;
d[x] = d[y] = K = TP = ;
DFS_1(x, , );
DFS_1(y, , );
build_t();
DFS_2(RT, edge[root].len); ///
_n = siz[x];
e_div(x);
_n = siz[y];
e_div(y);
return;
} int main() { srand();
scanf("%d", &n);
for(int i = ; i <= * n; i++) {
pw[i] = pw[i >> ] + ;
}
for(int i = ; i <= n; i++) {
rdP[i] = i;
}
std::random_shuffle(rdP + , rdP + n + );
t1.work();
t2.work();
t3.work();
/*if(n <= 3000) {
bf::solve();
printf("%lld\n", Ans);
return 0;
}
if(check_same()) {
same::solve();
printf("%lld\n", Ans);
return 0;
}
naive::solve();
fire::solve();*/
/// ---------------------------
Cnt = n;
rebuild(, );
_n = Cnt;
e_div();
printf("%lld\n", Ans);
return ;
}
AC代码
其实也不是很长......大概只有hope的一半多一点。虽然我没写hope......
LOJ#2339 通道的更多相关文章
- LOJ 2339 「WC2018」通道——边分治+虚树
题目:https://loj.ac/problem/2339 两棵树的话,可以用 CTSC2018 暴力写挂的方法,边分治+虚树.O(nlogn). 考虑怎么在这个方法上再加一棵树.发现很难弄. 看了 ...
- @loj - 2339@ 「WC2018」通道
目录 @desription@ @solution@ @accepted code@ @details@ @desription@ 11328 年,C 国的科学家们研发了一种高速传送通道,可以在很短的 ...
- 「WC2018」通道
没有代码能力... LOJ #2339 Luogu P4220 UOJ #347 题意 给定三棵树$ T1,T2,T3$,求一个点对$ (x,y)$使得$ T1.dist(x,y)+T2.dist(x ...
- LOJ#10064. 「一本通 3.1 例 1」黑暗城堡
LOJ#10064. 「一本通 3.1 例 1」黑暗城堡 题目描述 你知道黑暗城堡有$N$个房间,$M$条可以制造的双向通道,以及每条通道的长度. 城堡是树形的并且满足下面的条件: 设$D_i$为如果 ...
- Paypal开发中遇到请求被中止: 未能创建 SSL/TLS 安全通道及解决方案
最近在基于ASP.NET上开发了Paypal支付平台,在ASP.NET开发的过程中没有遇到这个问题,但是引用到MVC开发模式中的时候就出现了"未能创建 SSL/TLS 安全通道及解决方案&q ...
- JAVA NIO Socket通道
DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...
- 学习 opencv---(4) 分离颜色通道 && 多通道混合
上篇文章中我们讲到了使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作. 而为了更好地观察一些图像材料的特征,有时需要对R ...
- 关于QImage提取单色通道方法(vector)
转载请标明处: 作者:微微苏荷 本文地址:关于QImage提取单色通道方法(vector) 近日,用QT和mxnet结合做一个图像识别的demo.遇到需要把图片从QImage转为vector单色分离的 ...
- 基于暗通道优先算法的去雾应用(Matlab/C++)
基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理: 参见论文:Single Image Haze Removal Using Dark Channel Pri ...
随机推荐
- Python:运算类内建函数列举
1. divmod() python3.x版本中,整除运算用 “//”,取余可以用 “%”,在某些问题中要同时得到商和余数就需要两步运算,而使用divmod函数可以同时得到商和余数: 函数有两个参数d ...
- asp.net core自定义端口
asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...
- webmagic 基本的方法
WebMagic的结构分为Downloader.PageProcessor.Scheduler.Pipeline四大组件,并由Spider将它们彼此组织起来.这四大组件对应爬虫生命周期中的下载.处理. ...
- Serverless架构
什么是Serverless架构 Servlerless 架构是新兴的架构体系,在Serverless 架构中,开发者无需考虑服务器的问题,计算资源作为服务而不是服务器的概念出现,这样,开发者只需要关注 ...
- AnyDesk远程连接及异常处理
远程协助工具,用得最普遍的非QQ莫属,毕竟用户量在这里摆着的.不过,用户体验效果还不太理想,你懂得.接下来分享两个工具,一个是TeamViewer,另一个是AnyDesk.你更倾向于哪一款呢? 一.T ...
- Redis可视化工具 Redis Desktop Manager
1.前言 从接触Redis也有两年,平时就使用它来做缓存层,它给我的印象就是很强大,内置的数据结构很齐全,加上Redis5.0的到来,新增了很多特色功能.而Redis5.0最大的新特性就是多出了一个数 ...
- (转载)Python之道1-环境搭建与pycharm的配置django安装及MySQL数据库配置
近期做那个python的开发,今天就来简单的写一下开发路线的安装及配置, 开发路线 Python3.6.1+Pycharm5.0.6+Django1.11+MySQL5.7.18 1-安装Python ...
- OpenGL实例:三角形
OpenGL实例:三角形 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 更多请查看:计算机图形学 1. 三角形的旋转 #include <GL/ ...
- mmap:速度快+整块操作
mmap使得可以将设备内存映射到用户空间,从而使得用户程序获得访问硬件的能力,mmap的动作需要由内核中的驱动来实现.在使用mmap映射后,用户程序对给定范围的内存的读写就变成了对设备内存的读写,也就 ...
- CF786B Legacy(线段树优化建图)
嘟嘟嘟 省选Day1T2不仅考了字符串,还考了线段树优化建图.当时不会,现在赶快学一下. 线段树能优化的图就是像这道题一样,一个点像一个区间的点连边,或一个区间像一个点连边.一个个连就是\(O(n ^ ...