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; }