zoj 3649 lca与倍增dp
参考:http://www.xuebuyuan.com/609502.html
先说题意:
给出一幅图,求最大生成树,并在这棵树上进行查询操作:给出两个结点编号x和y,求从x到y的路径上,由每个结点的权值构成的序列中的极差大小——要求,被减数要在减数的后面,即形成序列{a1,a2…aj …ak…an},求ak-aj (k>=j)的最大值。
求路径,显然用到lca。
太孤陋寡闻,才知道原来倍增dp能用来求LCA。
用p[u][i]表示结点u的第1<< i 个祖先结点,则有递推如下:
for(int i=0;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1]。
在对图dfs的时候即完成递推。
要想求两个结点的lca,首先使得两结点高度相同,若二者的父亲结点不同,则一直向上查找。dep数组表示结点的深度。
int LCA(int a,int b){
if(dep[a]>dep[b]) swap(a,b);
if(dep[a]<dep[b]){
//这一部分使得dep[a]==dep[b]
int tmp=dep[b]-dep[a];
for(int i=0;i<POW;i++) if(tmp&(1<<i))
//这里从POW-1到0来遍历也是一样的
b=p[b][i];
}
if(a!=b){
for(int i=POW-1;i>=0;i--) if(p[a][i]!=p[b][i])
a=p[a][i],b=p[b][i];
a=p[a][0],b=p[b][0];
}
return a;
}
如此即返回结点的lca。
用倍增遍历的思路:
因为一段路被二进制分成了一截一截,或者说路径长度被用二进制表示了出来。而两个结点的深度差即为“路径长度”,所以只要tmp&(1<<i),则表示这是“路径”的其中一个结点,以此类推,从而得到两个深度相同的结点。
有了这个基础之后,用相同的方式构建——
mx数组,mx[u][i]表示从u到其第1<<i个祖先结点路径上的最大值
mn数组,mn[u][i]表示从u到其第1<<i个祖先结点路径上的最小值
dp数组,dp[u][i],表示从u到其第1<<i个祖先结点路径上的最大差值
dp2数组,dp2[u][i],表示从其第1<<i个祖先结点到u路径上的最大差值
构建好后是查询部分。给出结点x和y,获得lca。
则路径被分成两段—— x->lca->y。则有三种可能性:
x到lca上的最大差值;lca到y上的最大差值;x到y上的最大差值(即lca到y的最大值减去x到lca的最小值)。比较一下即可。
这题真心涨姿势。代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=3e4+,M=N<<,POW=,inf=21e8;
int mx[N][POW],mn[N][POW],p[N][POW],dp[N][POW],dp2[N][POW];
int head[N],nxt[M],to[M],cnt,val[N],vis[N],dep[N];
int n,m,q,fa[N];
struct Edge{
int u,v,w;
bool operator < (const Edge e) const{
return w>e.w;
}
}E[M];
void ini(int n){
memset(head,-,sizeof(head));
cnt=;
memset(vis,,sizeof(vis));
fill(p[],p[n+],);
fill(mx[],mx[n+],-inf);
fill(mn[],mn[n+],inf);
fill(dp[],dp[n+],-inf);
fill(dp2[],dp2[n+],-inf);
dep[]=;
}
int find_(int x){
return x==fa[x]?x:fa[x]=find_(fa[x]);
}
void addedge(int u,int v){
to[cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt++;
}
int Kruskal(){
for(int i=;i<=n;i++) fa[i]=i;
sort(E,E+m);
int sum=;
for(int i=;i<m;i++){
int a=find_(E[i].u),b=find_(E[i].v);
if(a!=b){
fa[a]=b;
addedge(E[i].u,E[i].v);
addedge(E[i].v,E[i].u);
sum+=E[i].w;
}
}
return sum;
}
void dfs(int u,int f){
dep[u]=dep[f]+;
vis[u]=;
for(int i=head[u];~i;i=nxt[i]) if(!vis[to[i]]){
int v=to[i];
p[v][]=u;
mx[v][]=max(val[u],val[v]);
mn[v][]=min(val[u],val[v]);
dp[v][]=val[u]-val[v];
dp2[v][]=val[v]-val[u];
for(int j=;j<POW;j++){
p[v][j]=p[p[v][j-]][j-];
mx[v][j]=max(mx[v][j-],mx[p[v][j-]][j-]);
mn[v][j]=min(mn[v][j-],mn[p[v][j-]][j-]); dp[v][j]=max(dp[v][j-],dp[p[v][j-]][j-]);
dp[v][j]=max(dp[v][j],mx[p[v][j-]][j-]-mn[v][j-]); dp2[v][j]=max(dp2[v][j-],dp2[p[v][j-]][j-]);
dp2[v][j]=max(dp2[v][j],mx[v][j-]-mn[p[v][j-]][j-]);
}
dfs(v,u);
}
}
int LCA(int a,int b){
//第一次看到这样的LCA,holy high
//有点不明觉厉
if(dep[a]>dep[b]) swap(a,b);
if(dep[a]<dep[b]){
//这一部分使得dep[a]==dep[b]
int tmp=dep[b]-dep[a];
for(int i=POW-;i>=;i--) if(tmp&(<<i))
b=p[b][i];
}
if(a!=b){
//如果高度相等,而a!=b
for(int i=POW-;i>=;i--) if(p[a][i]!=p[b][i])
a=p[a][i],b=p[b][i];
a=p[a][],b=p[b][];
}
return a;
}
int getmax(int x,int lca){
int ans=,tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,mx[x][i]);
x=p[x][i];
}
return ans;
}
int getmin(int x,int lca){
int ans=inf,tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=min(ans,mn[x][i]);
x=p[x][i];
}
return ans;
}
int getleft(int x,int lca){
int ans=,minn=inf;
int tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,dp[x][i]);
ans=max(ans,mx[x][i]-minn);
minn=min(minn,mn[x][i]);
x=p[x][i];
}
return ans;
}
int getright(int x,int lca){
int ans=,maxx=;
int tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,dp2[x][i]);
ans=max(ans,maxx-mn[x][i]);
maxx=max(maxx,mx[x][i]);
x=p[x][i];
}
return ans;
}
int main(){
freopen("in.txt","r",stdin);
while(~scanf("%d",&n)){
for(int i=;i<=n;i++)
scanf("%d",&val[i]);
ini(n);
scanf("%d",&m);
for(int i=;i<m;i++)
scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
printf("%d\n",Kruskal());
dfs(,);
scanf("%d",&q);
int x,y;
while(q--){
scanf("%d%d",&x,&y);
int lca=LCA(x,y);
int ans=getmax(y,lca)-getmin(x,lca);
ans=max(ans,getleft(x,lca));
ans=max(ans,getright(y,lca));
printf("%d\n",ans);
}
}
return ;
}
zoj 3649 lca与倍增dp的更多相关文章
- POJ3728The merchant (倍增)(LCA)(DP)(经典)(||并查集压缩路径?)
There are N cities in a country, and there is one and only one simple path between each pair of citi ...
- Social Net ZOJ - 3649
Social Net ZOJ - 3649 题意: 反正原题题意我是看不懂... 参考:http://www.cnblogs.com/names-yc/p/4922867.html 给出一幅图,求最大 ...
- Codeforces 1140G Double Tree 倍增 + dp
刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp 去维护它. 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点 ...
- P5024 保卫王国[倍增+dp]
窝当然不会ddp啦,要写这题当然是考虑优化裸dp啦,但是这题非常麻烦,于是变成了黑题. 首先,这个是没有上司的舞会模型,求图的带权最大独立集. 不考虑国王的限制条件,有 \[ dp[x][0]+=dp ...
- 关于LCA的倍增解法的笔记
emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主 ...
- LCA的倍增算法
LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...
- [模板]LCA的倍增求法解析
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 洛谷 P1613 跑路 (倍增 + DP + 最短路)
题目链接:P1613 跑路 题意 给定包含 \(n\) 个点和 \(m\) 条边的有向图,每条边的长度为 \(1\) 千米.每秒钟可以跑 \(2^k\) 千米,问从点 \(1\) 到点 \(n\) 最 ...
- ZOJ - 3649 树上倍增
题意:给出一个图,先求出最大生成树,然后多次询问树上路径\(u→v\)的有向最大极差\(max(a_i-a_j),i>j\),其中\(i\)和\(j\)指代节点在路径中出现的顺序 极差具有单调性 ...
随机推荐
- 【Nginx】定时器事件
转自:烟雨江南 Nginx事件管理主要是网络事件和定时器事件.下面介绍定时器事件管理,即超时管理. 为什么进行超时管理? Nginx有必要对可能发生超时的事件 进行统一管理,并在事件超时时作出相应的处 ...
- Visual Studio VS如何修改代码字体
工具-选项-环境-字体和颜色
- Web安全漏洞及攻击
背景介绍 先说一个在互联网上常见,但是普通人又不太理解的东西--“验证码”. 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell ...
- 使用HD/IDE层的ioctl接口获取磁盘容量get_hdd_max_sector
利用HD/IDE layer的ioctl函数接口获取HD/IDE的磁盘容量.HDIO_DRIVE_TASK 能发出訪问LBA地址的命令.但不能读写数据. #include <stdio.h&g ...
- 修改linux环境变量配置文件
发现error ImportError: dynamic module does not define module export function (PyInit_cv_bridge_boost) ...
- python 【第二篇】python基本数据类型
python数据类型 python的数据类型和大多数编程语言一样,有int,float,long,string但是python有三个特殊的数据类型:列表,元组,字典 如果不知道你的数据类型有什么方法: ...
- arcgis 发布地图服务
arcgis中,地图文档需要发布,才能为WEB所用. 咋发布呢? 1.在arcmap里面,点击 文件 - 共享为 - 服务 2.在弹出的对话框里选"发布服务",然后 3.这里面有点 ...
- B. Flag of Berland
B. Flag of Berland time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- USACO45 lights 电灯(折半搜索)
刚刚上一篇博客才D了队长一发,心里虚的慌......万分感谢队长给讲折半搜索!!听说这题可以高斯消元(可是我不会...貌似折半我也不会) 这题呢,一想到就是爆搜啦,然而,爆搜2^35必跪,折半搜索,就 ...
- 简单的处理git add ,git commit,git push 脚本
创建脚本lazygit.sh #!/bin/bash # 一次性处理git提交 #branch_name=`git symbolic-ref --short -q HEAD` branch_name= ...