UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树
跟隔壁通道是一个类型的
要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象……
第二棵树上的LCA显然是动不了的,因为没有其他的量跟它有关了,于是考虑将\(dep_x+dep_y-dep_{LCA(x,y)}\)魔改一下
它等于\(\frac{1}{2} (dep_x+dep_y+dist_{x,y})\),LCA就没了
然后做法就很明晰了
在第一棵树上边分治,为了叙述方便称实点为原树上的点,虚点为边分治构建过程中加入的点
设边分治到边\((x,y)\),与\(x\)相连的连通块中的实点点集为\(L\),与\(y\)相连的连通块中的实点点集为\(R\)
那么当前边贡献的答案就是\(\max\limits_{i \in L} \max\limits_{j \in R} \frac{1}{2}(dist_i + dist_j + dep_i + dep_j + w(x,y)) - dep'_{LCA'(i,j)}\),其中\(dist_i\)表示\(i\)到边\((x,y)\)的距离
接着考虑枚举\(LCA'(i,j)\)。对\(L \cup R\)在第二棵树上建立虚树进行树形DP,设\(f_{i,0/1}\)表示第二棵子树上\(i\)的子树中且属于\(L/R\)的点集中\(dist + dep\)的最大值,在合并两棵子树的时候贡献答案即可。
为了方便可以将\(w(x,y)\)丢进\(L\)或\(R\)的点权中
注意题目式子中\(x=y\)的情况
还有UOJ基数排序快LOJ快排快到底是个什么鬼
#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c)){
if(c == '-')
f = 1;
c = getchar();
}
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
}
const int MAXN = 3.7e5 + 9;
int N , CCC;
long long val[MAXN] , ans;
namespace Tree2{
struct Edge{
int end , upEd , w;
}Ed[MAXN << 1];
int head[MAXN] , dep[MAXN] , fir[MAXN] , ST[21][MAXN << 1] , logg2[MAXN << 1];
int cntEd , ts;
long long len[MAXN];
inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
Ed[cntEd].w = c;
}
void dfs(int x , int p){
dep[x] = dep[p] + 1;
ST[0][++ts] = x;
fir[x] = ts;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p){
len[Ed[i].end] = len[x] + Ed[i].w;
dfs(Ed[i].end , x);
ST[0][++ts] = x;
}
}
inline int cmp(int a , int b){
return dep[a] < dep[b] ? a : b;
}
void init_ST(){
for(int i = 2 ; i <= ts ; ++i)
logg2[i] = logg2[i >> 1] + 1;
for(int i = 1 ; 1 << i <= ts ; ++i)
for(int j = 1 ; j + (1 << i) - 1 <= ts ; ++j)
ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
}
inline int LCA(int x , int y){
x = fir[x];
y = fir[y];
if(x > y)
swap(x , y);
int t = logg2[y - x + 1];
return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
}
int st[MAXN] , top;
long long dp[MAXN][2];
vector < int > v , ch[MAXN];
void init(){
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read() , c = read();
addEd(a , b , c);
addEd(b , a , c);
}
dfs(1 , 0);
init_ST();
memset(dp , -0x3f , sizeof(dp));
ans = dp[0][0];
}
void solve(int x){
for(int i = 0 ; i < ch[x].size() ; ++i){
solve(ch[x][i]);
ans = max(ans , max(dp[x][0] + dp[ch[x][i]][1] , dp[x][1] + dp[ch[x][i]][0]) / 2 - len[x]);
dp[x][0] = max(dp[x][0] , dp[ch[x][i]][0]);
dp[x][1] = max(dp[x][1] , dp[ch[x][i]][1]);
dp[ch[x][i]][0] = dp[ch[x][i]][1] = dp[0][0];
}
ch[x].clear();
}
bool cmp1(int a , int b){
return fir[a] < fir[b];
}
int pot[11] , now[MAXN] , tmp[MAXN];
void bSort(){
int times = 1 , l = v.size();
for(int i = 0 ; i < l ; ++i)
now[i] = v[i];
for(int i = 0 ; i <= 6 ; ++i){
for(int j = 0 ; j <= 10 ; ++j)
pot[j] = 0;
for(int j = 0 ; j < l ; ++j)
++pot[(fir[now[j]] / times) % 10 + 1];
for(int j = 1 ; j <= 10 ; ++j)
pot[j] += pot[j - 1];
for(int j = 0 ; j < l ; ++j)
tmp[pot[(fir[now[j]] / times) % 10]++] = now[j];
memcpy(now , tmp , sizeof(int) * l);
times *= 10;
}
v.clear();
for(int i = 0 ; i < l ; ++i)
v.push_back(now[i]);
}
void work(const vector < int >& nd1 , const vector < int >& nd2 , int c){
++CCC;
for(int i = 0 ; i < nd1.size() ; ++i)
dp[nd1[i]][0] = val[nd1[i]] + c;
for(int i = 0 ; i < nd2.size() ; ++i)
dp[nd2[i]][1] = val[nd2[i]];
v.clear();
v.insert(v.end() , nd1.begin() , nd1.end());
v.insert(v.end() , nd2.begin() , nd2.end());
bSort();
//sort(v.begin() , v.end() , cmp1);
top = 0;
for(int i = 0 ; i < v.size() ; ++i){
if(top){
int p = LCA(st[top] , v[i]);
while(dep[st[top - 1]] >= dep[p]){
ch[st[top - 1]].push_back(st[top]);
--top;
}
if(dep[st[top]] > dep[p]){
ch[p].push_back(st[top]);
st[top] = p;
}
}
st[++top] = v[i];
}
while(top > 1){
ch[st[top - 1]].push_back(st[top]);
--top;
}
solve(st[1]);
dp[st[1]][0] = dp[st[1]][1] = dp[0][0];
top = 0;
}
}
namespace Tree1{
#define PII pair < int , int >
#define st first
#define nd second
struct Edge{
int end , upEd , w;
}Ed[MAXN << 2];
vector < PII > ch[MAXN];
int head[MAXN << 1] , cntN , cntEd = 1 , nowSz , minSz , minInd;
long long len[MAXN];
inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
Ed[cntEd].w = c;
}
void rebuild(int x , int p){
int cur = x;
for(int i = 0 ; i < ch[x].size() ; ++i)
if(ch[x][i].st != p){
len[ch[x][i].st] = len[x] + ch[x][i].nd;
int t = ++cntN;
addEd(cur , t , 0);
addEd(t , cur , 0);
addEd(t , ch[x][i].st , ch[x][i].nd);
addEd(ch[x][i].st , t , ch[x][i].nd);
cur = t;
rebuild(ch[x][i].st , x);
}
}
void init(){
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read() , c = read();
ch[a].push_back(PII(b , c));
ch[b].push_back(PII(a , c));
}
cntN = N;
rebuild(1 , 0);
}
bool vis[MAXN << 1];
void getSz(int x){
vis[x] = 1;
++nowSz;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
getSz(Ed[i].end);
vis[x] = 0;
}
int getRt(int x){
vis[x] = 1;
int sz = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
int t = getRt(Ed[i].end);
if(minSz > max(t , nowSz - t)){
minSz = max(t , nowSz - t);
minInd = i;
}
sz += t;
}
vis[x] = 0;
return sz;
}
void getNd(int x , long long l , vector < int > &v){
if(x <= N){
val[x] = l + len[x];
v.push_back(x);
}
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
getNd(Ed[i].end , l + Ed[i].w , v);
vis[x] = 0;
}
vector < int > nd1 , nd2;
void solve(int x){
nowSz = 0;
minSz = 1e9;
getSz(x);
if(nowSz == 1)
return;
getRt(x);
int p = Ed[minInd].end , q = Ed[minInd ^ 1].end;
Ed[minInd].end = q;
Ed[minInd ^ 1].end = p;
nd1.clear();
nd2.clear();
getNd(p , 0 , nd1);
getNd(q , 0 , nd2);
if(nd1.size() && nd2.size())
Tree2::work(nd1 , nd2 , Ed[minInd].w);
solve(p);
solve(q);
}
void work(){
solve(1);
for(int i = 1 ; i <= N ; ++i)
ans = max(ans , len[i] - Tree2::len[i]);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
N = read();
Tree1::init();
Tree2::init();
Tree1::work();
cout << ans;
return 0;
}
UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树的更多相关文章
- BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP
题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...
- LOJ 2553 「CTSC2018」暴力写挂——边分治+虚树
题目:https://loj.ac/problem/2553 第一棵树上的贡献就是链并,转化成 ( dep[ x ] + dep[ y ] + dis( x, y ) ) / 2 ,就可以在第一棵树上 ...
- UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并
原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$ ...
- 并不对劲的bzoj5341:loj2553:uoj400:p4565:[Ctsc2018]暴力写挂
题目大意 有两棵\(n\)(\(n\leq366666\))个节点的树,\(T\)和\(T'\),有边权 \(dep(i)\)表示在\(T\)中\(i\)号点到\(1\)号点的距离,\(dep'(i) ...
- [CTSC2018]暴力写挂——边分树合并
[CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分 ...
- [LOJ#2553][CTSC2018]暴力写挂
[LOJ#2553][CTSC2018]暴力写挂 试题描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...
- BZOJ5341: [Ctsc2018]暴力写挂
BZOJ5341: [Ctsc2018]暴力写挂 https://lydsy.com/JudgeOnline/problem.php?id=5341 分析: 学习边分治. 感觉边分治在多数情况下都能用 ...
- 题解 「CTSC2018暴力写挂」
题目传送门 题目大意 给出两个大小为 \(n\) 的树,求出: \[\max\{\text{depth}(x)+\text{depth}(y)-\text{depth}(\text{LCA}(x,y) ...
- bzoj 5341: [Ctsc2018]暴力写挂
Description Solution 边分治+边分树合并 这个题很多做法都是启发式合并的复杂度的,都有点卡 以前有个套路叫做线段树合并优化启发式合并,消掉一个 \(log\) 这个题思路类似,建出 ...
随机推荐
- 【代码笔记】Web-HTML-链接
一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- Linux 为linux enterprises 6安装图形桌面教程
为linux enterprises 6安装图形桌面教程 by:授客 QQ:1033553122 安装系统后发现没图形界面,安装Xwindow[为了避免权限不足,以root登录] 步骤1.启动图形界面 ...
- 腾讯云部署golang flow流程,vue.js+nginx+mysql+node.js
这次总算把js-ojus/flow的ui部署到腾讯云上,比较吐槽的就是,为啥这么复杂,vue.js前后端分离,比golang编写的部署方面复杂几万倍.真是浪费人生啊. golang+sqlite写的东 ...
- Chrome Inspect调试stetho出现空白的解决方法
stetho可以使用chrome调试webview,有网友反映国内不行,亲测了一下是有解决方法的: Chrome://inspect 打开后会发现stetho的页面: 点击inspect,如果没有Fa ...
- winsock编程学习笔记
以下部分转自博客http://blog.csdn.net/phunxm/article/details/5085869 套接字地址(sockaddr.sockaddr_in) /* * Structu ...
- Django ModelForm 小实例1
1.models.py ASSET_STATUS = ( (str(1), u"使用中"), (str(2), u"未使用"), (str(3), u" ...
- 06-OpenLDAP密码策略
阅读视图 openldap密码策略 OpenLDAP服务端定制密码策略 客户端策划策略实例 定义用户第一次登录就修改密码 问题排查手册 重点推荐官方文档 备注:本文依然承接系列文. 1. openld ...
- EF 更新部分字段写法
EF 更新部分字段写法 1.EF默认是查询出来,修改后保存: 2.设置不修改字段的IsModified为false,此方法不需要先从数据库查询出实体来(最优方法): db.Set<T>() ...
- 软件发布时的 GA、RC、Beta
今天在使用 ovirt 的时候,遇到了其 Pre-release 版本并看到如下版本号:ovirt-node-ng-image-update-4.2.7-0.1.rc1.el7.noarch.rpm ...
- Shell脚本应用(for、while循环语句和case分支语句)
1.for:读取不同的变量值,逐个执行同一组命令,直到取值完毕退出,变量值以空格分隔 语法: for 变量值 in 取值列表 do 命令序列 done 2.while:重复测试某个条件,成立则执 ...