【UOJ#400】暴力写挂
题意
两棵树 , 求出下面式子的最大值。
\]
Sol
边分治。
与第一棵树有关的信息比较多,所以对第一棵树边分。
\(LCA\) 在分治中不好处理 ,因为我们要换根还要快速合并路径信息,那么把式子变个形:
\]
这个样子的话在边分的过程中就可以直接把 一个点的深度与它到当前分治边的某个端点的距离作为点权了。这样我们只需要快速求出在第二棵树中选出两个不在同一集合中的点使得他们的权值减去他们的 LCA 在第二棵树中的深度的最大值。
直接虚树 + 树形dp 就可以了。
其实这个题目还是比较板的,没有太大的思维难度。
#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
struct edge{int to,next,w;};
const int N=4e5+10;
typedef long long ll;
typedef vector<int> ary;
const ll INF=1e16;
int n,Tn;
ll *Val,UPD;
int S[2][N];
ll ans=0;
namespace Tree2{
edge a[N<<1];
int head[N],cnt=0,bel[N];
int st[20][N<<1],id[N],log[N<<1],I=0,dep[N];ll dis[N];
inline void add(int x,int y,int z){a[++cnt]=(edge){y,head[x],z};head[x]=cnt;}
void dfs(int u,int fa){
st[0][++I]=u,id[u]=I;
for(int v,i=head[u];i;i=a[i].next){
v=a[i].to;if(v==fa) continue;
dep[v]=dep[u]+1,dis[v]=dis[u]+a[i].w;
dfs(v,u);st[0][++I]=u;
}
return;
}
inline int CK(int u,int v){if(!u||!v)return u|v;return dep[u]<dep[v]? u:v;}
inline int LCA(int u,int v){
if(u==v) return u;int l=id[u],r=id[v];if(l>r) swap(l,r);
int D=log[r-l+1]-1;
return CK(st[D][l],st[D][r-(1<<D)+1]);
}
inline ll Query(int u,int v){return dis[LCA(u,v)];}
void Build(){
int u,v,w;
for(int i=1;i<Tn;++i) init(u),init(v),init(w),add(u,v,w),add(v,u,w);
dfs(1,0);
for(int i=1;i<=I;++i) if((1<<log[i-1])<i) log[i]=log[i-1]+1;else log[i]=log[i-1];
for(int k=1;k<=log[I];++k)
for(int i=1;i+(1<<k)-1<=I;++i)
st[k][i]=CK(st[k-1][i],st[k-1][i+(1<<k-1)]);
cnt=0;Set(head,0);Set(bel,-1);
return;
}
namespace Vitual_Tree{
int que[N],tot=0;
int stk[N],top=0;
inline bool cmp(int u,int v){return id[u]<id[v];}
ll F[2][N];
inline void Insert(int u){
if(!top) return void(stk[++top]=u);
int lca=LCA(u,stk[top]);
if(lca==stk[top]) return void(stk[++top]=u);
while(top>=2&&id[stk[top-1]]>=id[lca]) add(stk[top-1],stk[top],0),--top;
if(stk[top]!=lca) add(lca,stk[top],0),stk[top]=lca;
stk[++top]=u;return;
}
void Dfs(int u){
F[0][u]=F[1][u]=-INF;
if(~bel[u]) F[bel[u]][u]=Val[u];
for(int v,i=head[u];i;i=a[i].next){
v=a[i].to;Dfs(v);
ans=max(ans,((F[0][u]+F[1][v]+UPD)/2)-dis[u]);
ans=max(ans,((F[1][u]+F[0][v]+UPD)/2)-dis[u]);
F[0][u]=max(F[0][u],F[0][v]);
F[1][u]=max(F[1][u],F[1][v]);
}
head[u]=0;bel[u]=-1;
}
void work(){tot=top=cnt=0;
for(int i=1;i<=S[0][0];++i) bel[S[0][i]]=0,que[++tot]=S[0][i];
for(int i=1;i<=S[1][0];++i) bel[S[1][i]]=1,que[++tot]=S[1][i];
sort(que+1,que+1+tot,cmp);
if(que[1]!=1) stk[top=1]=1;
for(int i=1;i<=tot;++i) Insert(que[i]);
while(top>1) add(stk[top-1],stk[top],0),--top;
Dfs(1);return;
}
}using Vitual_Tree::work;
}
namespace Tree1{
const int MAXN=N<<2;
edge a[MAXN<<1];
int head[MAXN],cnt=0,size[MAXN];ll dep[MAXN],dis[MAXN],Ret[MAXN];
bool vis[MAXN];
inline void add(int x,int y,int z){a[cnt]=(edge){y,head[x],z};head[x]=cnt++;}
inline void add_edge(int u,int v,int z){add(u,v,z),add(v,u,z);return;}
ary son[MAXN];
void dfs(int u,int fa){
for(int v,i=head[u];~i;i=a[i].next){
v=a[i].to;if(v==fa) continue;
son[u].push_back(v);dep[v]=dep[u]+a[i].w;Ret[v]=a[i].w;
dfs(v,u);
}
return;
}
int Cedge;
inline void Rebuild(){
Tn=n;cnt=0;Set(head,-1);
for(int i=1;i<=n;++i) {
int snum=son[i].size();
if(snum<=2) {
for(int j=0;j<snum;++j) add_edge(i,son[i][j],Ret[son[i][j]]);
}else{
int sl=++n;int sr=++n;
add_edge(i,sl,0),add_edge(i,sr,0);
for(int j=0;j<snum;++j) {
if(j&1) son[sl].push_back(son[i][j]);
else son[sr].push_back(son[i][j]);
}
}
}
return;
}
inline void Build(){
Set(head,-1);int u,v,w;
for(int i=1;i<n;++i) {init(u),init(v),init(w);add_edge(u,v,w);}
dfs(1,0);Rebuild();
return;
}
int Mx,Tot;
void Find(int u,int fa){
size[u]=1;
for(int v,i=head[u];~i;i=a[i].next){
v=a[i].to;if(v==fa||vis[i>>1]) continue;
Find(v,u);size[u]+=size[v];
int dat=max(size[v],Tot-size[v]);
if(dat<Mx) Mx=dat,Cedge=i;
}return;
}
void Dfs(int u,int fa,int*S,ll Dep){
dis[u]=dep[u]+Dep;
if(u<=Tn) S[++S[0]]=u;
for(int v,i=head[u];~i;i=a[i].next){
v=a[i].to;if(v==fa||vis[i>>1]) continue;
Dfs(v,u,S,Dep+a[i].w);
}
return;
}
inline void Divide(int u,int siz){
Mx=1e9;Tot=siz;Find(u,0);
if(Mx>=1e9) return;vis[Cedge>>1]=1;
int rtl=a[Cedge].to,rtr=a[Cedge^1].to;UPD=a[Cedge].w;
S[0][0]=S[1][0]=0;Dfs(rtl,0,S[0],0),Dfs(rtr,0,S[1],0);
Tree2::work();int szl=size[rtl];
Divide(rtl,szl);Divide(rtr,siz-szl);
return;
}
inline void Solve(){Val=dis;Divide(1,n);return;}
}
int main()
{
init(n);
Tree1::Build();
Tree2::Build();
Tree1::Solve();
for(int i=1;i<=Tn;++i) ans=max(ans,Tree1::dep[i]-Tree2::dis[i]);
cout<<ans<<endl;
return 0;
}
【UOJ#400】暴力写挂的更多相关文章
- 【CTSC2018】暴力写挂(边分治,虚树)
[CTSC2018]暴力写挂(边分治,虚树) 题面 UOJ BZOJ 洛谷 题解 发现第二棵树上的\(LCA\)的深度这玩意没法搞,那么枚举在第二棵树上的\(LCA\). 然后剩下的部分就是\(dep ...
- BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP
题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...
- [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 分析: 学习边分治. 感觉边分治在多数情况下都能用 ...
- Loj #2553. 「CTSC2018」暴力写挂
Loj #2553. 「CTSC2018」暴力写挂 题目描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...
- 「CTSC2018」暴力写挂
毫无$ Debug$能力 全世界就我会被卡空间.jpg LOJ #2553 UOJ #400 Luogu P4565 题意 给定两棵树$ T,T'$,求一组点对$ (x,y)$使得$deep(x)+d ...
- uoj#400. 【CTSC2018】暴力写挂(边分治)
传送门 做一道题学一堆东西.jpg 猫老师的题--暴力拿的分好像比打挂的正解多很多啊--我纯暴力+部分分已经能有80了--正解没调对之前一直只有10分→_→ 先说一下什么是边分治.这个其实类似于点分治 ...
- UOJ#400. 【CTSC2018】暴力写挂
传送门 看到要求两棵树的 \(lca\) 深度不太好操作 考虑枚举第二棵树的 \(lca\),这样剩下的都是只和第一棵树有关的 而注意到 \(dis(x,y)=d(x)+d(y)-2d(lca(x,y ...
- UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并
原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$ ...
随机推荐
- 【linux】cp 批量复制文件
[需求]: 有2个文件夹a,b,现在需要将a文件夹下的所有文件(aa.py,a2.py,a3.py)都复制到b文件夹(空文件夹) [解决办法]: 首先想到的是使用正则表达式,但是发现在linux中,只 ...
- Stream之filter、distinct、skip、map、flatMap、match、find、reduce
一.Stream之filter.distinct.skip: package com.cy.java8; import java.util.Arrays; import java.util.List; ...
- 阶段3 1.Mybatis_07.Mybatis的连接池及事务_3 mybatis连接池的分类
2.mybatis中的连接池 mybatis连接池提供了3种方式的配置: 配置的位置: 主配置文件SqlMapConfig.xml中的dataSourc ...
- RobotFramework 用例出错后继续操作
出错后退出 在默认情况下,当一个测试用例中的某个关键字返回错误时,这个测试用例就停止执行剩余的关键字.RF会继续执行下一个用例.这么做的好处是节省时间--反正这里出问题要返回来看了,再继续执行剩下的关 ...
- LoadRunner之关联
一.什么是关联 关联就是将服务器动态返回变化的值保存为一个参数以供后面需要用到的地方使用. 二.什么时候需要关联 1.服务器返回中存在动态变化的值,一般是类似session.token这样的无规则数据 ...
- tensorflow实践学习一
前言: 最近开始学习tensorflow框架,主要参考<TensorfFlow技术解析与实战>这本书,如果有同学需要这本书的PDF版,可以给我评论里留下邮箱,我看到了会发给你 正文 1.T ...
- Quartz任务调度的测试Demo1(含有配置文件的demo)
Quartz是一个作业任务调度的框架,所在项目组中“消息推送模块”使用到此框架,于是写个demo熟悉下quart的用法: 使用Spring框架来集成Quartz的任务调度任务. 1.搭建Spring框 ...
- 关于Pulsar与Kafka
在本系列的Pulsar和Kafka比较文章中,我将引导您完成我认为重要的几个领域,并且对于人们选择强大,高可用性,高性能的流式消息传递平台至关重要.消息传递模型(Messaging model)是用户 ...
- Android的Monkey和MonkeyRunner
本文部分解释性语段摘自网络百科或其它BLOG,语句内容网络随处可见,也不知道谁是初始原创,便不再署名出处,如有雷同,还请见谅. Monkey 什么是Monkey Monkey是Android中的一个命 ...
- 如何在centos6和centos7上部署nfs共享服务器和客户端
nfs共享服务为中小型企业在存储上提供了有效的节省空间,许多大型的网站也在使用nfs,如百度和阿里等,下面结合自己所学的知识,阐述如何在centos6和centos7下配置nfs.注:除了必要的说明外 ...