【CTSC2018】暴力写挂(边分治,虚树)

题面

UOJ

BZOJ

洛谷

题解

发现第二棵树上的\(LCA\)的深度这玩意没法搞,那么枚举在第二棵树上的\(LCA\)。

然后剩下的部分就是\(dep[x]+dep[y]-dep[lca]\)

这个玩意乱搞一下,就是\(\frac{1}{2}(dep[x]+dep[y]+dis(x,y))\)。

这样子就和\(LCA\)没有关系啦。

对于第一棵树进行边分治,分治两侧丢到第二棵树上建虚树做一遍树形\(dp\)求最大值就完事了???

然后常数巨大,最后换了一种方式写虚树,常数就小了很多(两遍\(sort\)太慢了),不过似乎可以把\(sort\)换成基数排序之类的可能会快些。

然后就卡过去了QwQ(其实只跑了3s)。

(代码里面注释的部分就是我原来写的虚树,,,,常数有点小大)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 400400
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n;
int S[2][MAX],top[2],type[MAX];
int lg[MAX<<1];
ll W[MAX],ans=-1e18;
namespace Tree2
{
struct Line{int v,next;ll w;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int dep[MAX];ll dis[MAX];
int dfn[MAX],low[MAX],tim;
int st[20][MAX<<1],sum,fir[MAX];
void dfs(int u,int ff)
{
dfn[u]=++tim;dep[u]=dep[ff]+1;st[0][++sum]=u;fir[u]=sum;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u),st[0][++sum]=u;
low[u]=tim;
}
int compare(int a,int b){return dep[a]<dep[b]?a:b;}
void pre()
{
for(int j=1;j<=lg[sum];++j)
for(int i=1;i+(1<<j)-1<=sum;++i)
st[j][i]=compare(st[j-1][i],st[j-1][i+(1<<(j-1))]);
memset(h,0,sizeof(h));
}
int LCA(int u,int v)
{
u=fir[u],v=fir[v];if(u>v)swap(u,v);
int k=lg[v-u+1];
return compare(st[k][u],st[k][v-(1<<k)+1]);
}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int Q[MAX<<1],T,Stack[MAX];bool vis[MAX];
ll f[MAX][2];
bool book[MAX];
void DP(int u,ll Pls)
{
f[u][0]=f[u][1]=-1e18;if(vis[u])f[u][type[u]]=W[u];
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;DP(v,Pls);
ans=max(ans,Pls+max(f[u][0]+f[v][1],f[u][1]+f[v][0])-2*dis[u]);
f[u][0]=max(f[u][0],f[v][0]);
f[u][1]=max(f[u][1],f[v][1]);
}
h[u]=0;vis[u]=false;
}
void Solve(ll Pls)
{
cnt=1;T=0;
for(int i=1;i<=top[0];++i)Q[++T]=S[0][i];
for(int i=1;i<=top[1];++i)Q[++T]=S[1][i];
for(int i=1;i<=T;++i)vis[Q[i]]=true;
sort(&Q[1],&Q[T+1],cmp);
int top=0;if(Q[1]!=1)Stack[++top]=1;
for(int i=1;i<=T;++i)
{
int u=Q[i],ff=LCA(u,Stack[top]);
while(top>1&&dep[Stack[top-1]]>=dep[ff])Add(Stack[top-1],Stack[top],0),--top;
if(ff!=Stack[top])Add(ff,Stack[top],0),Stack[top]=ff;
Stack[++top]=u;
}
while(top>1)Add(Stack[top-1],Stack[top],0),--top;
/*
for(int i=T,p;i>1;--i)
{
p=LCA(Q[i],Q[i-1]);if(book[p])continue;
book[p]=true;Q[++T]=p;
}
sort(&Q[1],&Q[T+1],cmp);
for(int i=1,top=0;i<=T;++i)
{
while(top&&low[Stack[top]]<dfn[Q[i]])--top;
if(top)Add(Stack[top],Q[i],dis[Q[i]]-dis[Stack[top]]);
Stack[++top]=Q[i];
}
*/
DP(1,Pls);
}
}
namespace Tree1
{
struct Line{int v,next,w;}e[MAX<<3];
int h[MAX<<2],cnt=1,V[MAX<<2];
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
vector<int> son[MAX<<2];
int N,size[MAX<<2];ll dis[MAX<<2],dep[MAX<<2];
void dfs(int u,int ff)
{
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
son[u].push_back(e[i].v),dep[e[i].v]=dep[u]+e[i].w,V[e[i].v]=e[i].w,dfs(e[i].v,u);
}
void ReBuild()
{
memset(h,0,sizeof(h));cnt=2;
for(int i=1;i<=N;++i)
{
int l=son[i].size();
if(l<=2)
for(int j=0;j<l;++j)
Add(i,son[i][j],V[son[i][j]]),Add(son[i][j],i,V[son[i][j]]);
else
{
int ls=++N,rs=++N;
Add(i,ls,0);Add(ls,i,0);Add(i,rs,0);Add(rs,i,0);
for(int j=0;j<l;++j)
if(j&1)son[ls].push_back(son[i][j]);
else son[rs].push_back(son[i][j]);
}
}
}
int rt,mx;
bool vis[MAX<<2];
void getroot(int u,int ff,int Size)
{
size[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff||vis[i>>1])continue;
getroot(v,u,Size);size[u]+=size[v];
int ret=max(size[v],Size-size[v]);
if(ret<mx)mx=ret,rt=i;
}
}
void dfs(int u,int ff,int opt)
{
z if(u<=n)S[opt][++top[opt]]=u,type[u]=opt;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff&&!vis[i>>1])
dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u,opt);
}
void Divide(int u,int Size)
{
mx=1e9;getroot(u,0,Size);
if(mx>=1e9)return;vis[rt>>1]=true;
int nw=rt,SS=Size-size[e[rt].v];
top[0]=top[1]=dis[e[rt].v]=dis[e[rt^1].v]=0;
dfs(e[rt].v,0,0);dfs(e[rt^1].v,0,1);
if(!top[0]&&!top[1])return;
for(int i=1;i<=top[0];++i)W[S[0][i]]+=dis[S[0][i]]+dep[S[0][i]];
for(int i=1;i<=top[1];++i)W[S[1][i]]+=dis[S[1][i]]+dep[S[1][i]];
Tree2::Solve(e[rt].w);
for(int i=1;i<=top[0];++i)W[S[0][i]]-=dis[S[0][i]]+dep[S[0][i]];
for(int i=1;i<=top[1];++i)W[S[1][i]]-=dis[S[1][i]]+dep[S[1][i]];
Divide(e[nw].v,size[e[nw].v]);
Divide(e[nw^1].v,SS);
}
}
int main()
{
n=read();Tree1::N=n;
for(int i=2;i<=n+n;++i)lg[i]=lg[i>>1]+1;
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
Tree1::Add(u,v,w);Tree1::Add(v,u,w);
}
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
Tree2::Add(u,v,w);Tree2::Add(v,u,w);
}
Tree1::dfs(1,0);Tree1::ReBuild();
Tree2::dfs(1,0);Tree2::pre();
Tree1::Divide(1,Tree1::N);
ans/=2;
for(int i=1;i<=n;++i)ans=max(ans,Tree1::dep[i]-Tree2::dis[i]);
printf("%lld\n",ans);
return 0;
}

【CTSC2018】暴力写挂(边分治,虚树)的更多相关文章

  1. BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP

    题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...

  2. LOJ 2553 「CTSC2018」暴力写挂——边分治+虚树

    题目:https://loj.ac/problem/2553 第一棵树上的贡献就是链并,转化成 ( dep[ x ] + dep[ y ] + dis( x, y ) ) / 2 ,就可以在第一棵树上 ...

  3. UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树

    传送门--UOJ 传送门--LOJ 跟隔壁通道是一个类型的 要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象-- 第二棵树上的LCA显然是动不了的,因为没有其他的量 ...

  4. UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并

    原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$ ...

  5. [CTSC2018]暴力写挂——边分树合并

    [CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分 ...

  6. [LOJ#2553][CTSC2018]暴力写挂

    [LOJ#2553][CTSC2018]暴力写挂 试题描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...

  7. BZOJ5341: [Ctsc2018]暴力写挂

    BZOJ5341: [Ctsc2018]暴力写挂 https://lydsy.com/JudgeOnline/problem.php?id=5341 分析: 学习边分治. 感觉边分治在多数情况下都能用 ...

  8. 题解 「CTSC2018暴力写挂」

    题目传送门 题目大意 给出两个大小为 \(n\) 的树,求出: \[\max\{\text{depth}(x)+\text{depth}(y)-\text{depth}(\text{LCA}(x,y) ...

  9. bzoj 5341: [Ctsc2018]暴力写挂

    Description Solution 边分治+边分树合并 这个题很多做法都是启发式合并的复杂度的,都有点卡 以前有个套路叫做线段树合并优化启发式合并,消掉一个 \(log\) 这个题思路类似,建出 ...

  10. 并不对劲的bzoj5341:loj2553:uoj400:p4565:[Ctsc2018]暴力写挂

    题目大意 有两棵\(n\)(\(n\leq366666\))个节点的树,\(T\)和\(T'\),有边权 \(dep(i)\)表示在\(T\)中\(i\)号点到\(1\)号点的距离,\(dep'(i) ...

随机推荐

  1. 【学习总结】Git学习-参考廖雪峰老师教程八-使用GitHub

    学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...

  2. JMeter学习FTP测试计划(转)

    FTP服务主要提供上传和下载功能.有时间需要我们测试服务器上传和下载的性能.在这里我通过JMeter做一个FTP测试计划的例子. 1.创建一个线程组 2.线程组--->添加--->配置元件 ...

  3. axios的增删改查。

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Linux 下面RPM 安装的SQLSERVER 修改字符集的方法

    1. 自己还是太low 2. 遇到问题 先 -h 处理 3. 发现登录报错, 怀疑是字符集的问题: 4. 计划是修改字符集 到 自己的环境可用的状态 使用命令 /opt/mssql/bin/mssql ...

  5. JS --- 如何获取一个对象的类型

    可以清楚的看到  拿到数字 字符串 对象 函数 数组 通过.slice(8,-1) 可以拿到类型的名称 ,可以做你想要的操作 Object.prototype.toString.call(222) & ...

  6. python之路--内置函数03

    一 . 正则表达式 匹配字符串 元字符 . 除了换行 \w 数字, 字母, 下划线 \d 数字 \s 空白符 \n \t \b 单词的边界 \W 非xxx \D \S [ ] 字符组 or的关系 [^ ...

  7. GlusterFS 安装配置

    1.磁盘格式化 mkfs.xfs -i size=512 /dev/vdb1 mkdir -p /data/brick1 cat > /etc/fstab <<EOF /dev/vd ...

  8. Ehlib(Delphi控件) v9.2.024 D7-XE10.2 免费绿色特别版

    下载地址:https://www.jb51.net/softs/579413.html#downintro2 EHLib是一个DELPHI 下的非常棒的第三方Grid控件,比DELPHI自带的强大许多 ...

  9. 2018-南京网络赛icpc-L题(分层最短路)

    题意:给你n个点,m条边的有向带权图,然后你每次可以选<=k条边的边权变成0,问你1到n的最短路: 解题思路:这道题基本上就是原题了呀,bzoj2763(无向图),解法就是拆点跑分层的最短路,比 ...

  10. python基础数据类型--dict 字典

    字典 字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据.python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必 ...