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. 小程序 height100% Android ios上的不同表现

    Android还是按原图显示 ios,会完全覆盖

  2. The Maximum Unreachable Node Set 【17南宁区域赛】 【二分匹配】

    题目链接 https://nanti.jisuanke.com/t/19979 题意 给出n个点 m 条边 求选出最大的点数使得这个点集之间 任意两点不可达 题目中给的边是有向边 思路 这道题 实际上 ...

  3. iOS 52个技巧学习心得笔记 第一章 熟悉OC

    1 .简单了解OC2 .在类的头文件中尽量少引入其他头文件3 .多用字面量语法 少用与之等价的方法 4 .多用类型常量 少用 #define 预处理指令5 .用枚举表示状态,选项,状态码 .简单了解O ...

  4. Swift进阶 - 12个技巧

    听说你已经学习Swift几个月了,有没有想更进一步成为Swift高手的想法?我这里有11招秘技,各位施主且听我慢慢道来,结个善缘. 1. 扩展(Extension) 任务: 求数字的平方. // 菜鸟 ...

  5. 【HackerRank】Pairs

    题目链接:Pairs 完全就是Two Sum问题的变形!Two Sum问题是要求数组中和正好等于K的两个数,这个是求数组中两个数的差正好等于K的两个数.总结其实就是“骑驴找马”的问题:即当前遍历ar[ ...

  6. [转载]OpenWRT使用wifidog实现强制认证的WIFI热点 | 半个橙子

    首先安装wifidog到OpenWRT的路由器: opkg update opkg install wifidog wifidog依赖下面这些模块: iptables-mod-extra iptabl ...

  7. 20145231《Java程序设计》第五次实验报告

    实验五 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验要求 基于Java Socket实现安全传输 基于TCP实现客户端和服 ...

  8. QGIS3.0.3+Qt5.9+VS2015_x64编译

    QGIS3.0.3+Qt5.9+VS2015_x64编译 参考:https://blog.csdn.net/u010670734/article/details/80241615 https://ww ...

  9. 《Inode与Block重要知识总结核心讲解》【转】

    本文转载自:https://blog.csdn.net/BlackEnn/article/details/50787092 1.查看/dev/sda1下磁盘分区的block大小: 2.查看单个inod ...

  10. Python之面向对象总结

    一.面向对象 1.面向过程 a.优点:极大的降低了写程序的复杂度,只需要顺着执行的步骤,堆叠代码即可 b.缺点:一套流水线或者流程就是来解决一个问题,代码就是牵一发而东莞全身 2.面向对象 a.优点: ...