【XSY1545】直径 虚树 DP
题目大意
给你一棵\(n\)个点的树,另外还有\(m\)棵树,第\(i\)棵树与原树的以\(r_i\)为根的子树形态相同。这\(m\)棵树之间也有连边,组成一颗大树。求这棵大树的直径长度。
\(n,m\leq 300000\)
题解
我们先用DP求出以原树的第\(i\)个点为根的子树的直径,那么以原树的第\(i\)个点为根的子树中的某个点为一个端点的最长路的另一个端点一定在直径的一端。
然后我们遍历第\(i\)棵树与其他树之间的边,求出每个点走到其他树的最长路。然后用虚树把这些边在第\(i\)棵树的端点和\(r_i\)连在一起,用DP合并。
zjt大爷:明明可以直接bfs两次为什么要DP?
时间复杂度:\(O((n+m)\log n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1200010;
struct list
{
int v[maxn];
int t[maxn];
int h[maxn];
int n;
list()
{
n=0;
memset(h,0,sizeof h);
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
struct list2
{
int x[maxn];
int y[maxn];
int x2[maxn];
int y2[maxn];
int t[maxn];
int h[maxn];
int n;
list2()
{
n=0;
memset(h,0,sizeof h);
}
void add(int a,int a2,int b,int b2)
{
n++;
x[n]=a;
x2[n]=a2;
y[n]=b;
y2[n]=b2;
t[n]=h[a];
h[a]=n;
}
};
int n,m;
namespace tree
{
list l;
struct p3
{
int d,x,y;
p3(int a=0,int b=0,int c=0)
{
d=a;
x=b;
y=c;
}
};
int operator <(p3 a,p3 b)
{
return a.d<b.d;
}
p3 a[maxn];
int d[maxn];
int f[maxn];
int st[600010][21];
int g[maxn];
int g2[maxn];
int ti;
int bg[maxn];
int ed[maxn];
int w[maxn];
int o[maxn];
int dmin(int x,int y)
{
return d[x]<d[y]?x:y;
}
void init()
{
ti=0;
memset(f,0,sizeof f);
}
void dfs(int x,int fa,int dep)
{
bg[x]=++ti;
w[ti]=x;
d[x]=dep;
f[x]=fa;
g[x]=1;
g2[x]=x;
a[x]=p3(1,x,x);
int i;
for(i=l.h[x];i;i=l.t[i])
if(l.v[i]!=fa)
{
dfs(l.v[i],x,dep+1);
a[x]=max(a[x],p3(g[x]+g[l.v[i]],g2[x],g2[l.v[i]]));
a[x]=max(a[x],a[l.v[i]]);
if(g[l.v[i]]+1>g[x])
{
g[x]=g[l.v[i]]+1;
g2[x]=g2[l.v[i]];
}
ti++;
w[ti]=x;
}
ed[x]=ti;
}
void buildst()
{
int i,j;
for(i=1;i<=ti;i++)
st[i][0]=w[i];
for(j=1;j<=20;j++)
for(i=1;i+(1<<j)-1<=ti;i++)
st[i][j]=dmin(st[i][j-1],st[i+(1<<(j-1))][j-1]);
o[1]=0;
for(i=2;i<=ti;i++)
o[i]=o[i/2]+1;
}
int getlca(int x,int y)
{
x=bg[x];
y=bg[y];
if(x>y)
swap(x,y);
int t=o[y-x+1];
return dmin(st[x][t],st[y-(1<<t)+1][t]);
}
int getdist(int x,int y)
{
int lca=getlca(x,y);
return d[x]+d[y]-2*d[lca]+1;
}
}
list2 l2;
int r[maxn];
ll ans;
ll f[maxn];
int stack[maxn];
int top;
int c[maxn];
int par[maxn];
ll g[maxn];
int cnt;
int tag[maxn];
int dfscmp(int x,int y)
{
return tree::bg[x]<tree::bg[y];
}
int getmaxdist(int x,int y)
{
return max(tree::getdist(y,tree::a[x].x),tree::getdist(y,tree::a[x].y));
}
void pushup(int x)
{
int v=par[x];
if(!v)
return;
ans=max(ans,g[v]+g[x]+tree::d[x]-tree::d[v]-1);
g[v]=max(g[v],g[x]+tree::d[x]-tree::d[v]);
}
void dp(int x,int x2,int fa)
{
f[x]=getmaxdist(r[x],x2);
int i;
for(i=l2.h[x];i;i=l2.t[i])
if(l2.y[i]!=fa)
dp(l2.y[i],l2.y2[i],x);
cnt=0;
c[++cnt]=x2;
for(i=l2.h[x];i;i=l2.t[i])
if(l2.y[i]!=fa)
{
c[++cnt]=l2.x2[i];
ans=max(ans,getmaxdist(r[x],l2.x2[i])+f[l2.y[i]]);
f[x]=max(f[x],f[l2.y[i]]+tree::getdist(x2,l2.x2[i]));
if(tag[l2.x2[i]]==x)
{
ans=max(ans,g[l2.x2[i]]+f[l2.y[i]]);
g[l2.x2[i]]=max(g[l2.x2[i]],f[l2.y[i]]+1);
}
else
{
tag[l2.x2[i]]=x;
g[l2.x2[i]]=f[l2.y[i]]+1;
}
}
if(tag[x2]!=x)
{
tag[x2]=x;
g[x2]=1;
}
sort(c+1,c+cnt+1,dfscmp);
cnt=unique(c+1,c+cnt+1)-c-1;
top=0;
int lca;
for(i=1;i<=cnt;i++)
{
if(!top)
{
stack[++top]=c[i];
par[c[i]]=0;
continue;
}
int lca=tree::getlca(c[i],c[i-1]);
while(top&&tree::d[stack[top]]>tree::d[lca])
{
if(tree::d[stack[top-1]]<tree::d[lca])
{
par[lca]=stack[top-1];
par[stack[top]]=lca;
g[lca]=1;
}
pushup(stack[top]);
top--;
}
if(tree::d[stack[top]]<tree::d[lca])
{
par[lca]=stack[top];
stack[++top]=lca;
}
par[c[i]]=stack[top];
stack[++top]=c[i];
}
while(top)
{
pushup(stack[top]);
top--;
}
}
int main()
{
memset(tag,0,sizeof tag);
freopen("diameter.in","r",stdin);
freopen("diameter.out","w",stdout);
tree::init();
scanf("%d%d",&n,&m);
int i,x,y,x2,y2;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
tree::l.add(x,y);
tree::l.add(y,x);
}
tree::dfs(1,0,1);
tree::buildst();
for(i=1;i<=m;i++)
scanf("%d",&r[i]);
for(i=1;i<m;i++)
{
scanf("%d%d%d%d",&x,&x2,&y,&y2);
l2.add(x,x2,y,y2);
l2.add(y,y2,x,x2);
}
ans=0;
dp(1,r[1],0);
printf("%lld\n",ans);
return 0;
}
【XSY1545】直径 虚树 DP的更多相关文章
- bzoj 3572世界树 虚树+dp
题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- [BZOJ5287][HNOI2018]毒瘤(虚树DP)
暴力枚举非树边取值做DP可得75. 注意到每次枚举出一个容斥状态的时候,都要做大量重复操作. 建立虚树,预处理出虚树上两点间的转移系数.也可动态DP解决. 树上倍增.动态DP.虚树DP似乎是这种问题的 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ 3572 [HNOI2014]世界树 (虚树+DP)
题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...
- 洛谷P2495 [SDOI2011]消耗战(虚树dp)
P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...
- bzoj 3611 [Heoi2014]大工程(虚树+DP)
3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 408 Solved: 190[Submit][Status] ...
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 645 Solved: 362[Submit][Status] ...
随机推荐
- Python—json模块
用于序列化的两个模块 json,用于字符串 和 python数据类型间进行转换 pickle,用于python特有的类型 和 python的数据类型间进行转换 Json模块提供了四个功能:dumps. ...
- 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)
链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
- Python编码与变量
(一)Python执行的方式 Window: 在CMD里面,使用 Python + 相对路径/绝对路径 在解释器里面,直接输入,一行代码一行代码的解释 Linux: 明确地指出用Python解释器来执 ...
- p9半幺群
如何不理解划红线的地方?第二个划红线地方,请举一个例子 1.0不是幺元 2.f(1)=2, f(2)=1, f(3)=3, g(1)=2, g(2)=3, g(3)=1 fg不等于gf
- CRM系统(第一部分)
阅读目录 1.需求分析 2.数据库表设计 3.起步 4.录入数据 5.知识点 1.需求分析 CRM客户关系管理软件---> 学员管理 用户:企业内部用户 用户量: 业务场景: 2.数据库表设 ...
- 敏捷开发、DevOps相关书籍——书单
自己瞎整理的一些书单,都是豆瓣评分比较高的书,可以作为选择的一个参考. 书名 豆瓣链接 持续交付:发布可靠软件的系统方法 https://book.douban.com/subject/6862062 ...
- spring aop学习记录
许多AOP框架,比较常用的是Spring AOP 与AspectJ.这里主要学习的Spring AOP. 关于AOP 日志.事务.安全验证这些通用的.散步在系统各处的需要在实现业务逻辑时关注的事情称为 ...
- [转帖]Nginx rewrite模块深入浅出详解
Nginx rewrite模块深入浅出详解 https://www.cnblogs.com/beyang/p/7832460.html rewrite模块(ngx_http_rewrite_modul ...
- Day 5-2 类的继承和派生,重用
类的继承 派生 在子类中重用父类 组合 抽象类 定义: 继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创建新类的方式,在python中,新 ...
- C# Note15:设置Window图标的正确方式
Windows Presentation Foundation(WPF)独立应用程序有两种类型的图标: 一个程序集(assembly) 图标,通过在应用程序的项目构建文件中使用<Applicat ...