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\)指代节点在路径中出现的顺序 极差具有单调性 ...
随机推荐
- HDU 5280 Senior's Array
Senior's Array Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) T ...
- Windows环境下QWT安装及配置
** 1.QWT下载路径 **:https://sourceforge.net/projects/qwt/ 主要下载这三个文件:qwt-6.1.2.zip.qwt-6.1.2.pdf,qwt-6.1. ...
- Vs2017添加引用时报错 未能正确加载“ReferenceManagerPackage”包。
Vs2017添加引用时报错未能正确加载“ReferenceManagerPackage”包. 最近新装了2017,开始前几天还好, 可是最近在添加引用时,报错 -------------------- ...
- Node 即学即用 笔记 思维导图
Node即学即用 REPL(Read-Evaluate-Print-Loop) console.log .clear .help .exit require('http') ...
- mysql工作原理(网络搜索整理的)
原文网址:Mysql 工作原理 原文网址:MySQL运行原理与基础架构 mysql基本用法原文网址:MySQL(一):基本原理 SQL 语句执行过程 数据库通常不会被直接使用,而是由其他编程语言通过S ...
- 【Java报错】Message: 3 字节的 UTF-8 序列的字节 2 无效
报错logs 2015-03-10 10:15:32,360 ERROR [qtp32195030-27] [InvokeAfterValve.java:55] - javax.xml.stream. ...
- js来获取所有屏幕适配的总结
"屏幕分辨率为:"+screen.width+"*"+screen.height "屏幕可用大小:"+screen.availWidth+& ...
- mysql10---索引优化
D:\MYSQL\mysql-winx64\data\WIN-20171216YUR-slow.log是慢日志: ; ; # Time: :.472000Z # # Query_time: Rows_ ...
- Tju 4119. HDFS
4119. HDFS Time Limit: 5.0 Seconds Memory Limit: 5000KTotal Runs: 225 Accepted Runs: 77 In HDF ...
- CentOS 7下修改rabbitmq打开文件数量方法
以下为使用systemd的修改方法: 1.系统层修改: 通过修改sysctl配置,提高系统的打开文件数量 vim /etc/sysctl.conf,添加: fs.file-max = 65535 ...