BZOJ5341: [Ctsc2018]暴力写挂

https://lydsy.com/JudgeOnline/problem.php?id=5341

分析:

  • 学习边分治。
  • 感觉边分治在多数情况下都能用转二叉树后的点分治来写,不过反正都转二叉树了,不如写边分治。
  • 对于这道题,最大化\(dep_x+dep_y-dep(lca1)+dep(lca2)\)
  • \((dis(x,y)+dep_x+dep_y+dep(lca2))/2\)
  • 其中\(dis(x,y)+dep_x+dep_y\)可以在分治过程中拆成\(w_x\)和\(w_y\)。
  • 对第二棵树建虚树,枚举lca2,转化成求子树里颜色不同、在不同子树的两个点点权和最大。
  • 多叉转二叉和之后的虚树\(dp\)什么的详见代码。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iostream>
using namespace std;
#define N 400050
#define db(x) cerr<<#x<<" = "<<x<<endl
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {
int x=0,f=1; char s=nc();
while(s<'0') {if(s=='-')f=-1; s=nc();}
while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
return x*f;
}
typedef long long ll;
int n,c[N],a[N],is[N];
ll w[N],ans;
const ll inf=1ll<<55;
struct E {
int t,v;
E() {}
E(int t_,int v_) {t=t_,v=v_;}
};
void run();
struct A {
#define M 800050
vector<E>V[N];
int head[M],to[M<<1],nxt[M<<1],cnt,val[M<<1],m;
int vis[M<<1],root,siz[M],fk[M<<1],tot;ll dis[M];
void init(){cnt=1;}
inline void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void rb(int x,int y) {
int i,lim=V[x].size(),so=0,lst=0;
for(i=0;i<lim;i++) if(V[x][i].t!=y) {
int t=V[x][i].t,v=V[x][i].v;
so++;
if(so==1) {
add(x,t,v), add(t,x,v); lst=x;
}else if(so==lim-(x!=1)) {
add(lst,t,v), add(t,lst,v);
}else {
m++; add(lst,m,0); add(m,lst,0); add(m,t,v); add(t,m,v); lst=m;
}
}for(i=0;i<lim;i++)if(V[x][i].t!=y)rb(V[x][i].t,x);
}void gd(int x,int y) {int i;for(i=head[x];i;i=nxt[i])if(to[i]!=y)dis[to[i]]=dis[x]+val[i],gd(to[i],x);}
void gr(int x,int y) {
int i; siz[x]=1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!vis[i]) {
gr(to[i],x); siz[x]+=siz[to[i]]; fk[i]=max(siz[to[i]],tot-siz[to[i]]);
if(fk[i]<fk[root]) root=i;
}
}
void d1(int x,int y,ll d,int o) {
int i;
if(x<=n) c[x]=o, w[x]=dis[x]+d, a[++a[0]]=x, is[x]=1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!vis[i]) {
d1(to[i],x,d+val[i],o);
}
}
void dc(int x) {
root=0;gr(x,0);if(!root)return;
int p=root,all=tot;
vis[p]=vis[p^1]=1;
a[0]=0;
d1(to[p],0,val[p],1);
d1(to[p^1],0,0,2);
run();
int sz=siz[to[p]];
tot=sz; dc(to[p]);
tot=all-sz; dc(to[p^1]);
}
void pre() {
int i,x,y,z;
for(i=1;i<n;i++) x=rd(),y=rd(),z=rd(),V[x].push_back(E(y,z)),V[y].push_back(E(x,z));
m=n; rb(1,0);
gd(1,0);
}
void Wk() {
tot=m; fk[0]=1<<30; dc(1);
}
}t1;
inline bool cmp(const int&,const int&);
struct B {
int head[N],to[N<<1],nxt[N<<1],cnt,val[N<<1];
int dfn[N],fa[N],dep[N],siz[N],son[N],top[N];
int S[N],tp;
ll dis[N],f[N][3];
inline void add(int u,int v,int w) {to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;}
inline void add(int u,int v) {to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;}
void d1(int x,int y) {
dfn[x]=++dfn[0]; fa[x]=y; siz[x]=1; int i; dep[x]=dep[y]+1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
dis[to[i]]=dis[x]+val[i];
d1(to[i],x); siz[x]+=siz[to[i]];
if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
}
}
void d2(int x,int t) {
top[x]=t;int i;if(son[x]) d2(son[x],t);
for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) d2(to[i],to[i]);
}
int lca(int x,int y) {
for(;top[x]!=top[y];y=fa[top[y]]) if(dep[top[x]]>dep[top[y]]) swap(x,y); return dep[x]<dep[y]?x:y;
}
void Wk() {
int i,x,y,z; for(i=1;i<n;i++) x=rd(),y=rd(),z=rd(),add(x,y,z),add(y,x,z);
d1(1,0); d2(1,1); memset(head,0,sizeof(head)); cnt=0;
}
void dp(int x) {
int i;
if(is[x]) f[x][c[x]]=w[x],f[x][3-c[x]]=-inf;
else f[x][1]=f[x][2]=-inf;
for(i=head[x];i;i=nxt[i]) {
dp(to[i]);
ans=max(ans,f[x][1]+f[to[i]][2]-2*dis[x]);
ans=max(ans,f[x][2]+f[to[i]][1]-2*dis[x]);
f[x][1]=max(f[x][1],f[to[i]][1]); f[x][2]=max(f[x][2],f[to[i]][2]);
}
head[x]=0; is[x]=0;
}
void mk() {
cnt=0;
int i;
sort(a+1,a+a[0]+1,cmp);
S[tp=1]=1;
for(i=1;i<=a[0];i++) {
int x=a[i],y=lca(x,S[tp]);
while(dep[y]<dep[S[tp]]) {
if(dep[y]>=dep[S[tp-1]]) {
add(y,S[tp]); tp--;
if(S[tp]!=y) S[++tp]=y;
break;
}
add(S[tp-1],S[tp]); tp--;
}
if(S[tp]!=x) S[++tp]=x;
}
while(tp>1) add(S[tp-1],S[tp]),tp--;
dp(1);
}
}t2;
inline bool cmp(const int &x,const int &y) {return t2.dfn[x]<t2.dfn[y];}
void run() {t2.mk();}
int main() {
n=rd();
t1.init();
t1.pre();
t2.Wk();
t1.Wk();
ans>>=1;
int i;
for(i=1;i<=n;i++) {
ans=max(ans,t1.dis[i]-t2.dis[i]);
}
printf("%lld\n",ans);
}

BZOJ5341: [Ctsc2018]暴力写挂的更多相关文章

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

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

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

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

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

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

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

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

  5. [CTSC2018]暴力写挂

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

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

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

  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. Capslock and Esc

    将Caps Lock转换成Esc(windows and linux) 1. linux 下将Caps Lock 转换成Esc 作为一个vimer,Caps Lock对我(还有其他很多人)来说根本就是 ...

  2. Linux软件包管理 RMP包

    RPM 包的安装虽然很方便和快捷,但是依赖性实在是很麻烦,尤其是库文件依赖,还要去 rpmfind 网站査找库文件到底属于哪个 RPM 包,从而导致 RPM 包的安装非常烦琐.那么,有没有可以自动解决 ...

  3. class_alias--为一个类创建别名

    class_alias--为一个类创建别名 bool class_alias ( string $original , string $alias [, bool $autoload = TRUE ] ...

  4. INSPIRED启示录 读书笔记 - 第36章 可用性与美感

    两者缺一不可 交互设计和视觉设计完全是两回事 视觉设计可以满足用户的情感需求 良好的用户体验是交互设计师和视觉设计师合作的结果.他们共同配合产品经理定义产品

  5. vmxnet3 丢包处理

    https://vswitchzero.com/2017/09/26/vmxnet3-rx-ring-buffer-exhaustion-and-packet-loss/

  6. python里两种遍历目录的方法

    os.walk 函数声明:os.walk(top,topdown=True,onerror=None) (1)参数top表示需要遍历的顶级目录的路径. (2)参数topdown的默认值是“True”表 ...

  7. vector对象

    vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,例如vector<int> 定义和初始化vector对象: vector<T> v1    ...

  8. jenkins tomcat

    tomcat增加用户配置: <role rolename="tomcat"/> <role rolename="role1"/> < ...

  9. 算法总结之 将单链表的每K个节点之间逆序

    给定一个单链表的表头节点head,实现一个调整单链表的函数,是的每k个节点之间逆序,如果最后不够k个节点一组,则不调整最后几个节点 思路: 如果k的值小于2,不调整.k<1 没有意义,k==1代 ...

  10. R语言笔记005——计算描述性统计量

    数据的分布特征: 分布的集中趋势,反应各数据向其中心值靠拢或聚集的程度(平均数,中位数,四分位数,众数) 分布的离散程度,反应各数据远离其中心值的趋势(极差,四分位差,方差,标准差,离散系数) 分布的 ...