标签:acm algorithm hihocoder lca tarjan
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
10 25 100 100
题意:在一棵树上,给出你每条边的权值,每次询问(u,v)之间距离多少。
分析:LCA+tarjan离线算法,模板题。用个数组depth[]来记录根节点走到每个点的路程,然后找出(u,v)的最近公共祖先LCA(u,v)。
那么,quary(u,v) = depth[u] + depth[v] - 2 * depth[LCA(u,v)]。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
代码清单:
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<string>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
const int maxv = 1e5 + 5;
struct Edge{ int v,next,id; }edge[2*maxn];
struct Graph{ int v,next,dis; }graph[2*maxn];
int T;
int N,M;
int a,b,c;
int father[maxn];
int num,numq;
int head[maxn],headq[maxn];
pair<int,int>e[maxn];
int color[maxn],ans[maxn],depth[maxn];
bool vis[maxn];
int Find(int x){ return x!=father[x] ? father[x]=Find(father[x]) : father[x]; }
void tarjan_LCA(int u){
vis[u]=true;color[u]=1;
for(int i=headq[u];i!=-1;i=edge[i].next){
int ID=edge[i].id;
if(ans[ID]!=-1) continue;
int v=edge[i].v;
if(color[v]==0) continue;
if(color[v]==1) ans[ID]=v;
if(color[v]==2) ans[ID]=Find(v);
}
for(int i=head[u];i!=-1;i=graph[i].next){
int vv=graph[i].v;
int dis=graph[i].dis;
if(!vis[vv]){
depth[vv]=depth[u]+dis;
tarjan_LCA(vv);
color[vv]=2;
father[vv]=u;
}
}
}
void add(int u,int v,int dis){
graph[num].v=v;
graph[num].dis=dis;
graph[num].next=head[u];
head[u]=num++;
}
void addq(int u,int v,int idx){
edge[numq].v=v;
edge[numq].id=idx;
edge[numq].next=headq[u];
headq[u]=numq++;
}
void init(){
for(int i=1;i<=maxn;i++) father[i]=i;
memset(edge,0,sizeof(edge));
memset(graph,0,sizeof(graph));
memset(head,-1,sizeof(head));
memset(headq,-1,sizeof(headq));
memset(color,0,sizeof(color));
memset(ans,-1,sizeof(ans));
memset(depth,0,sizeof(depth));
memset(vis,false,sizeof(vis));
num=numq=0;
}
void input(){
scanf("%d%d",&N,&M);
for(int i=1;i<N;i++){
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
for(int i=1;i<=M;i++){
scanf("%d%d",&a,&b);
e[i].first=a;e[i].second=b;
addq(a,b,i);
addq(b,a,i);
}
}
void solve(){
tarjan_LCA(1);
for(int i=1;i<=M;i++){
a=e[i].first;
b=e[i].second;
printf("%d\n",depth[a]+depth[b]-2*depth[ans[i]]);
}
}
int main(){
scanf("%d",&T);
while(T--){
init();
input();
solve();
}return 0;
}
5 3 2 1 3 2 2 4 3 5 2 3 1 4 4 5
Not connected 6HintHint Huge input, scanf recommended.
分析:LCA+tarjan离线算法,模板题。每次找个没有标记的点作为根节点跑一遍tarjan的时候记得把color数组初始化。因为之前染色的点属于前一棵树,跟当前的那棵树没有关系。
注意:此题用vector估计会MLE,所以用数组存。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874
代码清单:
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<string>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn = 10000 + 5;
const int maxv = 10000 + 5;
const int maxq = 1000000 + 5;
struct MAX{
int v,d;
MAX(){}
MAX(int v,int d){
this -> v = v;
this -> d = d;
}
};
struct Q{ int v,id,next; }quary[2*maxq];
struct e{ int v,dis,next; }graph[2*maxn];
int n,m,q;
int a,b,c;
int father[maxn];
bool vis[maxn];
int ans[maxq];
int color[maxn];
int depth[maxn];
int nume,numq;
int heade[maxn];
int headq[maxn];
void init(){
for(int i=1;i<=maxn;i++) father[i]=i;
memset(ans,-1,sizeof(ans));
memset(color,0,sizeof(color));
memset(depth,0,sizeof(depth));
memset(vis,false,sizeof(vis));
memset(graph,0,sizeof(graph));
memset(quary,0,sizeof(quary));
memset(heade,-1,sizeof(heade));
memset(headq,-1,sizeof(headq));
nume=numq=0;
}
void add_E(int u,int v,int dis){
graph[nume].v=v;
graph[nume].dis=dis;
graph[nume].next=heade[u];
heade[u]=nume++;
}
void add_Q(int u,int v,int id){
quary[numq].v=v;
quary[numq].id=id;
quary[numq].next=headq[u];
headq[u]=numq++;
}
void input(){
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
add_E(a,b,c);
add_E(b,a,c);
}
for(int i=1;i<=q;i++){
scanf("%d%d",&a,&b);
add_Q(a,b,i);
add_Q(b,a,i);
}
}
int Find(int x){ return x!=father[x] ? father[x]=Find(father[x]) : father[x]; }
void tarjan(int u){
color[u]=1;
vis[u]=true;
for(int i=headq[u];i!=-1;i=quary[i].next){
int ID=quary[i].id;
if(ans[ID]!=-1) continue;
int v=quary[i].v;
if(color[v]==0) continue;
if(color[v]==1) ans[ID]=depth[u]-depth[v];
if(color[v]==2) ans[ID]=depth[u]+depth[v]-2*depth[Find(v)];
}
for(int i=heade[u];i!=-1;i=graph[i].next){
int vv=graph[i].v;
int dis=graph[i].dis;
if(!vis[vv]){
depth[vv]=depth[u]+dis;
tarjan(vv);
color[vv]=2;
father[vv]=u;
}
}
}
void solve(){
for(int i=1;i<=n;i++){
if(!vis[i]){ memset(color,0,sizeof(color)); tarjan(i); }
}
for(int i=1;i<=q;i++){
if(ans[i]==-1) printf("Not connected\n");
else printf("%d\n",ans[i]);
}
}
int main(){
while(scanf("%d%d%d",&n,&m,&q)!=EOF){
init();
input();
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU_2586 && HDU_2874 (LCA+tarjan)
标签:acm algorithm hihocoder lca tarjan
原文地址:http://blog.csdn.net/jhgkjhg_ugtdk77/article/details/47258577