题目大意

有两棵\(n\)(\(n\leq366666\))个节点的树,\(T\)和\(T'\),有边权

\(dep(i)\)表示在\(T\)中\(i\)号点到\(1\)号点的距离,\(dep'(i)\)表示在\(T'\)中\(i\)号点到\(1\)号点的距离

\(lca(i,j)\)表示在\(T\)中\(i\)号点到\(j\)号点的简单路径上到\(1\)号点边数最少的点,\(lca'(i,j)\)表示在\(T'\)中\(i\)号点到\(j\)号点的简单路径上到\(1\)号点边数最少的点

求\(max(dep(x)+dep(y)-dep(lca(x,y))-dep'(lca'(x,y)))\)

题解

\(dis(x,y)\)表示在\(T\)中\(x\)号点到\(y\)号点的距离

原式变为\(max(\frac{1}{2}*(dep(x)+dep(y)-dis(x,y))-dep'(lca'(x,y)))\)

枚举两点在\(T'\)中的lca,那么剩下的部分只和两点在\(T\)中的深度、距离有关,与\(T\)中lca无关,将\(dep(x),dep(y)\)看成点权,\(T\)变为无根树,可以进行点分治或边分治,求出一对点在\(T\)中的距离加两点点权的最大值。

也就是说,要先计算\(T'\)中某点前\(k-1\)棵子树和该点第\(k\)棵子树对答案的影响,然后再将第\(k\)棵子树与前\(k-1\)棵子树合并

这个可以在点(边)分树在合并时计算

点分树合并没有复杂度保证;边分树长得像线段树,合并时也可以类似线段树合并

代码
#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 366670
#define maxn2 (maxn<<1)
#define maxn4 (maxn<<2)
#define LL long long
#define mi (l+r>>1)
#define ls(u) (son[u][0])
#define rs(u) (son[u][1])
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
struct edge{int nxt,v;int w;}e0[maxn2],e1[maxn2],e2[maxn4];
int n,siz[maxn2],vis[maxn4],cnt0,cnt1,cnt2,fir[maxn],fir1[maxn],fir2[maxn2],st[22][maxn4],lg[maxn4],tim,dfn[maxn2],dep[maxn2],wk,mnsz,nd,nowsiz;
int to[maxn4*5],bac[maxn2],son[maxn4*22][2],rt[maxn2],cntnd;
LL dep2[maxn2],len[maxn4*22],ans,maxm,inf[2];
void ade(int u1,int v1,int w1){e0[cnt0].v=v1,e0[cnt0].w=w1,e0[cnt0].nxt=fir[u1],fir[u1]=cnt0++;}
void ade1(int u1,int v1,int w1){e1[cnt1].v=v1,e1[cnt1].w=w1,e1[cnt1].nxt=fir1[u1],fir1[u1]=cnt1++;}
void ade2(int u1,int v1,int w1){e2[cnt2].v=v1,e2[cnt2].w=w1,e2[cnt2].nxt=fir2[u1],fir2[u1]=cnt2++;}
void getsiz(int u,int fa)
{
siz[u]=1;
for(int k=fir2[u];k!=-1;k=e2[k].nxt)
if(e2[k].v!=fa&&!vis[k]&&!vis[k^1])
{
getsiz(e2[k].v,u),siz[u]+=siz[e2[k].v];
if(max(siz[e2[k].v],nowsiz-siz[e2[k].v])<mnsz)mnsz=max(siz[e2[k].v],nowsiz-siz[e2[k].v]),wk=k;
}
}
int Lca2(int x,int y)
{
x=dfn[x],y=dfn[y];
if(x>y)swap(x,y);
return dep[st[lg[y-x+1]][x]]<dep[st[lg[y-x+1]][y-(1<<lg[y-x+1])+1]]?st[lg[y-x+1]][x]:st[lg[y-x+1]][y-(1<<lg[y-x+1])+1];
}
inline LL dis2(int x,int y){return dep2[x]+dep2[y]-2ll*dep2[Lca2(x,y)];}
void getwt(int now,int u)
{
if(nowsiz==1){to[u]=-now;bac[now]=u;return;}
mnsz=nd+1;
getsiz(now,0);int nowk=wk;
to[u]=nowk;
vis[nowk]=vis[nowk^1]=1;
int siz1=siz[e2[nowk].v],siz2=siz[e2[nowk^1].v];
if(siz1>siz2)siz1=nowsiz-siz2;
else siz2=nowsiz-siz1;
nowsiz=siz1,getwt(e2[nowk].v,u<<1),nowsiz=siz2,getwt(e2[nowk^1].v,u<<1|1);
}
void get2(int u,int fa)
{
int f=0,lst;
for(int k=fir[u];k!=-1;k=e0[k].nxt)if(e0[k].v!=fa)lst=e0[k].v;
for(int k=fir[u];k!=-1;k=e0[k].nxt)
if(e0[k].v!=fa)
{
if(!f)ade2(u,e0[k].v,e0[k].w),ade2(e0[k].v,u,e0[k].w),f=u;
else
{
if(lst!=e0[k].v)nd++,ade2(f,nd,0),ade2(nd,f,0),ade2(nd,e0[k].v,e0[k].w),ade2(e0[k].v,nd,e0[k].w),f=nd;
else ade2(f,e0[k].v,e0[k].w),ade2(e0[k].v,f,e0[k].w);
}
get2(e0[k].v,u);
}
}
void getst(int u)
{
dfn[u]=++tim;st[0][tim]=u;
for(int k=fir2[u];k!=-1;k=e2[k].nxt)
if(!dfn[e2[k].v])dep2[e2[k].v]=dep2[u]+(LL)e2[k].w,dep[e2[k].v]=dep[u]+1,getst(e2[k].v),st[0][++tim]=u;
}
int getrt(int node)
{
int now=bac[node],u,lst=0,f;
while(now)
{
u=++cntnd;
if(lst)son[u][f]=lst;
if(now>>1)len[u]=dis2(node,e2[to[(now>>1)]].v)+dep2[node];
f=0,lst=u;
if((((now>>1)<<1)|1)==now)f=1;
now>>=1;
}
return u;
}
void merge(int ua,int ub)
{
if(ls(ua)&&rs(ub))maxm=max(maxm,(len[ls(ua)]+len[rs(ub)])/2ll);
if(rs(ua)&&ls(ub))maxm=max(maxm,(len[rs(ua)]+len[ls(ub)])/2ll);
len[ua]=max(len[ua],len[ub]);
if(ls(ub))
{
if(ls(ua))merge(ls(ua),ls(ub));
else ls(ua)=ls(ub);
}
if(rs(ub))
{
if(rs(ua))merge(rs(ua),rs(ub));
else rs(ua)=rs(ub);
}
return;
}
void getans(int u,int fa,LL nowdep)
{
rt[u]=getrt(u);
for(int k=fir1[u];k!=-1;k=e1[k].nxt)
if(e1[k].v!=fa)getans(e1[k].v,u,nowdep+e1[k].w);
maxm=dep2[u];
for(int k=fir1[u];k!=-1;k=e1[k].nxt)
if(e1[k].v!=fa)merge(rt[u],rt[e1[k].v]);
ans=max(ans,maxm-nowdep);
}
int main()
{
memset(fir,-1,sizeof(fir));
memset(fir1,-1,sizeof(fir1));
memset(fir2,-1,sizeof(fir2));
memset(inf,0x7f,sizeof(inf));
n=nd=read();
rep(i,1,n-1){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);}
rep(i,1,n-1){int x=read(),y=read(),z=read();ade1(x,y,z),ade1(y,x,z);}
get2(1,0);
getst(1); lg[0]=-1;
rep(i,1,tim)lg[i]=lg[i>>1]+1;
rep(k,1,lg[tim])for(int i=1;i+(1<<k)-1<=tim;++i)
st[k][i]=dep[st[k-1][i]]<dep[st[k-1][i+(1<<k-1)]]?st[k-1][i]:st[k-1][i+(1<<k-1)];
nowsiz=nd;ans=-inf[0];
getwt(1,1);
getans(1,0,0);
write(ans);
return 0;
}

并不对劲的bzoj5341:loj2553:uoj400:p4565:[Ctsc2018]暴力写挂的更多相关文章

  1. BZOJ5341: [Ctsc2018]暴力写挂

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

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

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

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

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

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

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

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

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

  6. [CTSC2018]暴力写挂

    题目描述 www.lydsy.com/JudgeOnline/upload/201805/day1(1).pdf 题解 首先来看这个我们要最大化的东西. deep[u]+deep[v]-deep[lc ...

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

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

  8. 题解 「CTSC2018暴力写挂」

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

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

    [CTSC2018]暴力写挂(边分治,虚树) 题面 UOJ BZOJ 洛谷 题解 发现第二棵树上的\(LCA\)的深度这玩意没法搞,那么枚举在第二棵树上的\(LCA\). 然后剩下的部分就是\(dep ...

随机推荐

  1. 生产环境下lnmp的权限说明

    https://www.cnblogs.com/zrp2013/p/4183546.html 有关权限说明:-rwxrw-r‐-1 root root 1213 Feb 2 09:39 50.html ...

  2. hdu 1711kmp裸题

    #include<stdio.h> #define N 1000050 int text[N],t[N],next[N],n,m; void getnext() { int j=0,k=- ...

  3. Linux(5):正则表达式 & 权限

    正则表达式: 特殊符号: '' ---> 所见即所得,里面的内容都会被原封不动的输出出来 "" ---> 与单引号类似,但其中的特殊符号会被解析运行 `` ---> ...

  4. Codeforces889C. Maximum Element

    $n \leq 2000000$的排列,问有多少满足:存在个$i$,使得$p_i \neq n$,且$p_j<p_i,j \in [i+1,i+K]$,$K \leq 2000000$是给定常数 ...

  5. CF788E:New task

    n个数字中,每个数有数字A和属性B,每次操作将某个点x的属性B改变为0或1,求满足这样要求的子序列的个数: 下标a<b<c<d<e,而Aa<=Ab=Ac=Ad>=A ...

  6. linux 开机启动脚本或者服务

    https://blog.csdn.net/zhuchunyan_aijia/article/details/53811368

  7. POJ 2513 【字典树】【欧拉回路】

    题意: 有很多棒子,两端有颜色,告诉你两端的颜色,让你把这些棒子拼接起来要求相邻的接点的两个颜色是一样的. 问能否拼接成功. 思路: 将颜色看作节点,将棒子看作边,寻找欧拉通路. 保证图的连通性的时候 ...

  8. java内存区域和对象的产生

    一直被java中内存组成弄的头晕眼花,这里总结下都有哪些,先上图片 程序计数器 小块内存,线程执行字节码的信号指示器,以此获取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复都要依赖他 ...

  9. 转 常见hash算法的原理

    散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Hash table,也叫 ...

  10. [PythonCode]扫描局域网的alive ip地址

    内网的主机都是自己主动分配ip地址,有时候须要查看下有那些ip在使用,就写了个简单的脚本. linux和windows下都能够用,用多线程来ping1-255全部的地址,效率不高.2分钟左右. 先凑合 ...