[LCA & RMQ] [NOIP2013] 货车运输
首先看到这题, 由于要最大, 肯定是求最大生成树
那么 o(n2) dfs 求任意点对之间的最小边是可以想到的
但是看看数据范围肯定TLE
于是暴力出来咯, 不过要注意query的时候判断的时候要 m+-1 但是递归下去要用m , 可以画图举特例分析
1AC 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smin(x,tmp) x=min((x),(tmp))
const int INF=0x3f3f3f3f;
const int maxn=;
const int maxm=; int fa[maxn];
int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
inline bool union_find(int x,int y)
{
int t1=find(x),t2=find(y);
if(t1==t2) return false;
fa[t2]=t1;
return true;
}
map <pair<int,int>,int> g;
struct Edge
{
int to,next;
int val;
}edge[maxm<<];
int head[maxn];
int maxedge;
inline void addedge(int u,int v,int c)
{
edge[++maxedge]=(Edge){v,head[u],c};
head[u]=maxedge;
edge[++maxedge]=(Edge){u,head[v],c};
head[v]=maxedge;
g[make_pair(u,v)]=c;
g[make_pair(v,u)]=c;
} struct Road
{
int from,to;
int cost;
bool operator < (const Road t) const
{
return cost>t.cost;// querying the Biggest MST !!!!
}
}road[maxm];
int n,m; int f[maxn],son[maxn],size[maxn],depth[maxn];
int top[maxn],id[maxn],rid[maxn];
int maxnode;//for segment tree (one-demensional array)
int dfs1(int u,int father,int deep)
{
f[u]=father,size[u]=,depth[u]=deep;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==father) continue;
size[u]+=dfs1(v,u,deep+);
if(!son[u]||size[son[u]]<size[v]) son[u]=v;
}
return size[u];
}
void dfs2(int u,int tp)
{
top[u]=tp;id[u]=++maxnode;rid[maxnode]=u;// non de mixer la id-rid !!
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==f[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int tree[maxn<<];//min
void build(int root,int l,int r)
{
if(r-l==)
{
tree[root]=g[make_pair(rid[l],rid[r])];
return;
}
int m=(l+r)>>;
build(root<<,l,m);
build(root<<|,m,r);
tree[root]=min(tree[root<<],tree[root<<|]);
}
int query(int root,int l,int r,int x,int y)//query min
{
if(x==y) return INF;//must!! when query the same node !!!!!!
if(x<=l&&r<=y) return tree[root];
int m=(l+r)>>;
int t1=INF,t2=INF;
if(x<=m-&&l<=y) t1=query(root<<,l,m,x,y);//here too, use x<=m-1 in case stucking at m
if(y>=m+&&r>=x) t2=query(root<<|,m,r,x,y);//be conscious of m or m+1, query m but judge m+1
return min(t1,t2);
}
int Find(int u,int v)//find min
{
int t1=top[u],t2=top[v];
int ret=INF;
while(t1^t2)
{
if(depth[t1]<depth[t2]) swap(t1,t2),swap(u,v);
smin(ret,query(,,maxnode,id[t1],id[u]));
smin(ret,g[make_pair(t1,f[t1])]);
u=f[t1];
t1=top[u];
}
if(depth[u]<depth[v]) swap(u,v);
return min(ret,query(,,maxnode,id[v],id[u]));
} inline void init()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++) scanf("%d%d%d",&road[i].from,&road[i].to,&road[i].cost);
for(int i=;i<=n;i++) fa[i]=i;
memset(head,-,sizeof(head));
maxedge=-;
}
void kruskal()
{
sort(road+,road+m+);
int pos=,tot=;
while(pos<=m && tot^(n-))
{
if(union_find(road[pos].from,road[pos].to)) tot++,addedge(road[pos].from,road[pos].to,road[pos].cost);
pos++;
}
}
bool vis[maxn];//for union_find
void build_forest()
{
for(int i=;i<=n;i++)
{
int father=find(i);
if(!vis[father])
{
vis[father]=true;
dfs1(father,,);
dfs2(father,father);
}
}
build(,,maxnode);
}
int main()
{
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
init();
kruskal();
build_forest();
int q;
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(find(x)^find(y)) printf("-1\n");
else printf("%d\n",Find(x,y));
}
return ;
}
但是NOIP正解一定不是链剖, 此题要用到 LCA 的 ST 倍增算法, 并且属于精确的查询,没有重叠部分, 可以用sum等进行替换, 边dfs边更新
用 f[i][j] = f[f[i][j-1]][j-1] 保存 i 前面的第2i 节点, 与普通 RMQ 不同
用 dp[i][j] = min ( dp[i][j-1] , dp[f[i][j-1]][j-1] ) 来维护倍增的最小值 ( 当然 sum 也一样 , 因为精确求范围, 满足区间加 )
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smin(x,tmp) x=min((x),(tmp))
#define smax(x,tmp) x=max((x),(tmp))
const int INF=0x3f3f3f3f;
const int maxn=;
const int maxm=;
const int maxd=; int fa[maxn];
int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
inline bool union_find(int x,int y)
{
int t1=find(x),t2=find(y);
if(t1==t2) return false;
fa[t2]=t1;
return true;
} struct Edge
{
int to,next;
int val;
}edge[maxm<<];
int head[maxn];
int maxedge;
inline void addedge(int u,int v,int c)
{
edge[++maxedge]=(Edge){v,head[u],c};
head[u]=maxedge;
edge[++maxedge]=(Edge){u,head[v],c};
head[v]=maxedge;
} struct Road
{
int from,to;
int cost;
bool operator < (const Road t) const
{
return cost>t.cost;
}
}road[maxm];
int n,m; inline void init()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++) scanf("%d%d%d",&road[i].from,&road[i].to,&road[i].cost);
for(int i=;i<=n;i++) fa[i]=i;
memset(head,-,sizeof(head));
maxedge=-;
}
void kruskal()
{
sort(road+,road+m+);
int pos=,tot=;
while(pos<=m && tot^(n-))
{
if(union_find(road[pos].from,road[pos].to)) tot++,addedge(road[pos].from,road[pos].to,road[pos].cost);
pos++;
}
} int f[maxn][maxd+],dp[maxn][maxd+]; // the node 2^j after u
int depth[maxn];
void dfs(int u,int deep)
{
depth[u]=deep;
for(int k=;(<<k)<=n;k++)
{
f[u][k] = f[f[u][k-]][k-];
dp[u][k] = min(dp[u][k-] , dp[f[u][k-]][k-]);
}
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!depth[v])
{
f[v][]=u;dp[v][]=edge[i].val;//initialize here rather than in the former context!! no considering the roor coz INF is INF, not changing and not visiting the value!!
dfs(v,deep+);
}
}
} int Find(int u,int v)
{
int ans=INF;
if(depth[u] < depth[v]) swap(u,v);// making the u is deeper!!
// make u v at the same depth
for(int k=maxd;k>=;k--) // k>=0 here!! or cannot jump at the same depth!!!
if(depth[v] <= depth[f[u][k]]) // f[0] = 0, indicates its beyond the root!!
{
smin( ans , dp[u][k] );
u=f[u][k];
}
if(u == v) return ans; //special judge of one of them is the LCA
// jump at the same time
for(int k=maxd;k>=;k--) // k>=0 here too!!
if(f[u][k] ^ f[v][k])
{
smin(ans , min( dp[u][k] , dp[v][k] ) );
u = f[u][k];
v = f[v][k];
}
return min( ans , min(dp[u][] , dp[v][])); // u v this time is the F1 of LCA
} int main()
{
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
init();
kruskal();
memset(dp,0x3f,sizeof(dp));
for(int i=;i<=n;i++)
if(!depth[i]) dfs(i,);
int q;
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(find(x)^find(y)) printf("-1\n");
else printf("%d\n",Find(x,y));
}
return ;
}
然后的话粘一发 LCA 裸题 HDU 2874
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn=;
struct Edge
{
int to,next;
int val;
}edge[maxn*maxn];
int head[maxn];
int maxedge;
inline void addedge(int u,int v,int c)
{
edge[++maxedge]=(Edge){v,head[u],c};
head[u]=maxedge;
edge[++maxedge]=(Edge){u,head[v],c};
head[v]=maxedge;
}
int n,m,q;
int fa[maxn];
int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
bool union_find(int x,int y)
{
int t1=find(x),t2=find(y);
if(t1==t2) return false;
fa[t2]=t1;
return true;
}
int maxnode;
int dfn[maxn],ver[maxn<<];//dfn: first visit maxnode, ver: reverse function of dfn, indicating the number of vertex
int depth[maxn<<],dis[maxn];//depth: the depth of dfn, dis: from root to vertex
inline bool init()
{
if(!~scanf("%d%d%d",&n,&m,&q)) return false;
for(int i=;i<=n;i++) fa[i]=i;
memset(head,-,sizeof(head));
memset(dfn,,sizeof(dfn));
maxedge=-;maxnode=;
for(int i=;i<=m;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c);
union_find(u,v);
}
return true;
}
void dfs(int u,int deep)
{
dfn[u]=++maxnode;ver[maxnode]=u;depth[maxnode]=deep;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(dfn[v]) continue;
dis[v]=dis[u]+edge[i].val;
dfs(v,deep+);
depth[++maxnode]=deep;ver[maxnode]=u;
}
}
const int maxdepth=;
int dp[maxn<<][maxdepth];
void ST(int n)// n=::maxnode
{
for(int i=;i<=n;i++) dp[i][]=i;
for(int j=;(<<j)<=n;j++)//careful of the limits
for(int i=;i+(<<j)-<=n;i++)//careful of the limits by y=dp[i+(1<<j-1)][j-1] and the limit of i+(1<<j)-1<=n, must -1 'coz the i+(1<<j)-1 is possible to be n!!
{
int x=dp[i][j-],y=dp[i+(<<j-)][j-];
dp[i][j]=depth[x]<depth[y]?x:y;
}
}
inline int RMQ(int l,int r)
{
int k=;
while(<<(k+)<=r-l+) k++;// careful of the limits!!
int x=dp[l][k],y=dp[r-(<<k)+][k];
return depth[x]<depth[y]?x:y;
}
inline int LCA(int u,int v)
{
int x=dfn[u],y=dfn[v];
if(x>y) swap(x,y);
int root=RMQ(x,y);
return ver[root];
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
while(init())
{
for(int i=;i<=n;i++)
if(!dfn[i]) dfs(i,);
ST(maxnode);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(find(x)^find(y)) printf("Not connected\n");
else printf("%d\n",dis[x]+dis[y]-(dis[LCA(x,y)]<<));
}
}
return ;
}
[LCA & RMQ] [NOIP2013] 货车运输的更多相关文章
- [Luogu 1967] NOIP2013 货车运输
[Luogu 1967] NOIP2013 货车运输 一年多前令我十分头大的老题终于可以随手切掉了- 然而我这码风又变毒瘤了,我也很绝望. 看着一年前不带类不加空格不空行的清纯码风啊,时光也好像回去了 ...
- NOIP2013 货车运输(最大生成树,倍增)
NOIP2013 货车运输(最大生成树,倍增) A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道 ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- NOIP2013 货车运输
3.货车运输 (truck.cpp/c/pas) [问题描述] A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货 ...
- Codevs3278[NOIP2013]货车运输
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 ...
- 【洛谷P1967】[NOIP2013]货车运输
货车运输 题目链接 显然,从一点走到另一点的路径中,最小值最大的路径一定在它的最大生成树上 所以要先求出最大生成树,再在生成树上找最近公共祖先,同时求出最小值. #include<iostrea ...
- noip2013货车运输
P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过 ...
- NOIP2013货车运输[lca&&kruskal]
题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...
- NOIP2013 货车运输 LCA倍增+最大生成树
#include <cstdio> #include <iostream> #include <ctime> #include <vector> #in ...
随机推荐
- Oracle- UPDATE FROM讲解
在表的更新操作中,在很多情况下需要在表达式中引用要更新的表以外的数据.像sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通 ...
- Windows 窗体启动和关闭的事件顺序
本文系转载学习. 对于关注对 Windows 窗体应用程序中引发的每个事件按次序进行处理的开发人员来说,事件引发的顺序特别重要.当某种情况需要小心处理事件时(如重绘窗体的某些部分时),必须知道事件在运 ...
- spring aop 的一个demo(未完,待完善)
假设我们有这样的一个场景 : 对于一个类的众多方法,有些方法需要从缓存读取数据,有些则需要直接从数据库读取数据.怎样实现呢? 实现方案有多种.下面我说下常见的几种实现方案 : 1.直接采用spring ...
- jqueryui.position.js源代码分析
近期要写前端组件了.狂砍各种组件源代码,这里分析一款jqueryui中的posistion插件,注意,它不是jqueryui widget,首先看下源代码整体结构图 1.看到$.fn.position ...
- 详解Android Handler的使用
我们进行Android开发时,Handler可以说是使用非常频繁的一个概念,它的用处不言而喻.本文就详细介绍Handler的基本概念和用法. Handler的基本概念 Handler主 ...
- 每天进步一点点——负载均衡之DNS域名解析
转载请说明出处:http://blog.csdn.net/cywosp/article/details/38017027 在上一篇文章(http://blog.csdn.net/cywosp/ ...
- Asp.Net 之 获取GridView行的DataKeys
1.后台任意一个位置获取GridView行的主键值 foreach (GridViewRow row in GridView1.Rows) { string order_Id=this.GridVie ...
- TreeMap与TreeSet的实现
虽然TreeMap 是 Map 接口的常用实现类,而 TreeSet 是 Set 接口的常用实现类,但TreeSet底层是通过 TreeMap来实现的,因此二者的实现方式完全一样.而 TreeMap ...
- C#导入导出Excel表的数据
一:C#导入导出EXCEL文件的类 代码如下: 首先将Microsoft Excel 14.0 Object Library 引用导入 using System; using System.Data; ...
- 【原】Spring与MongoDB集成:仓库
上一篇文章用介绍了如何配置spring-data-mongo连接到MongoDB上,如何创建MongoTemplate.MongoTemplate就相当于一个通用的仓库,可以持久化业务对象. 在spr ...