【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]$ ...
随机推荐
- 你的第一个Quartz程序
package org.quartz.examples.example1; import java.util.Date; import org.slf4j.Logger; import org.slf ...
- spring boot 整合saml2
项目是国外的一位大神发布到githut上,这里只是对项目代码的分析与学习,也算是一种强化记忆 附上 githut地址:https://github.com/OpenConext/Mujina 项目分为 ...
- C#中winform下利用ArcEngine调用ArcGIS Server发布的服务 AE9.3
主要使用了AE中的IAGSServerOject接口及IMapServer接口.Private void GetServerTest_Click(object sender, EventArgs e) ...
- 阶段3 1.Mybatis_06.使用Mybatis完成DAO层的开发_9 typeAliases标签和package标签
配置别名 上面制定了好了别名后,映射文件就可以简写了.不区分大小写 皆可以小写也可以大写 大小写混着也可以 测试 package 直接把com.itheima.domain下面所有的类都注册了 可以使 ...
- Python学习之==>常用字符串方法
1.常用字符串方法 a = '\n 字 符 串 \n\n' b = a.strip() # 默认去掉字符串两边的空格和换行符 c = a.lstrip() # 默认去掉字符串左边的空格和换行符 d = ...
- delphi : 窗体的close,free,destroy
一.我用application.create(TForm2,Form2)语句,创建了Form2,可是调用了Form2.close后,重新调用Form2.show. 刚才所创建的Form2仍然存在.问为 ...
- Android专项测试监控资源
版本号 V 1.1.0 Android性能测试分为两类:1.一类为rom版本(系统)的性能测试2.一类为应用app的性能测试(本次主要关注点为app的性能测试) Android的app性能测试包括的测 ...
- cocos2dx基础篇(20) 扩展动作CCGridAction
[3.x] (1)去掉"CC" [CCGridAction] CCGridAction有两个子类:CCGrid3DAction.CCTiledGrid3DAction.而我 ...
- IP子网的划分
一.划分子网的具体步骤 已知192.168.1.0/24,划分8个子网(一个ip划分8个子网,即网络位不再是24位)1100 0000.1010 1000.0000 0001.0000 00001 . ...
- Java第一周总结
通过两周的Java学习最深刻的体会就是Java好像要比C要简单一些. 然后这两周我学习到了很多东西,李老师第一次上课就给我们介绍了Java的发展历程,同时还有Java工具jdk的发展历程. Java语 ...