1、Targan算法(离线)

http://poj.org/problem?id=1470

/*伪代码
Tarjan(u)//marge和find为并查集合并函数和查找函数
{
for each(u,v) //访问所有u子节点v
{
Tarjan(v); //继续往下遍历
marge(u,v); //合并v到u上
标记v被访问过;
}
for each(u,e) //访问所有和u有询问关系的e
{
如果e被访问过;
u,e的最近公共祖先为find(e);
}
} */
//思想
/*
1.任选一个点为根节点,从根节点开始。
2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。
3.若是v还有子节点,返回2,否则下一步。
4.合并v到u上。
5.寻找与当前点u有询问关系的点v。
6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。
*/ #include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define ll long long const int MAXN=1010;
const int MAXQ=500010; //并查集部分
int F[MAXN];//初始化为-1
int find(int x)
{
if(F[x]==-1)return x;
return F[x]=find(F[x]);
}
//merge
void bing(int u,int v)
{
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
F[t1]=t2;
}
}
//****************
//建图部分
bool vis[MAXN];
int ancestor[MAXN];//存储查询过程节点的祖先
struct Edge
{
int to,next;
}edge[MAXN<<2];
int head[MAXN],tot;
void add_edge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
} //离线查询部分 struct Query
{
int q,next;
int index;// 查询编号
}query[MAXQ<<1]; int answer[MAXQ];//存储最后的每个查询的公共祖先,下标0,Q-1
int h[MAXQ];
int tt;int Q; void add_query(int u,int v,int index)
{
query[tt].q=v;
query[tt].next=h[u];
query[tt].index=index;
h[u]=tt++;
query[tt].q=u;
query[tt].next=h[v];
query[tt].index=index;
h[v]=tt++;
} //LCA部分
void init()
{
tot=0;
memset(head,-1,sizeof(head));
tt=0;
memset(h,-1,sizeof(h));
memset(vis,false,sizeof(vis));
memset(F,-1,sizeof(F));
memset(ancestor,0,sizeof(ancestor));
} void LCA(int u)
{
ancestor[u]=u;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v])continue;
LCA(v);
bing(u,v);
ancestor[find(u)]=u;//?
}
for(int i=h[u];i!=-1;i=query[i].next)
{
int v=query[i].q;
if(vis[v])
{
answer[query[i].index]=ancestor[find(v)];
}
}
} bool flag[MAXN];
int Count_num[MAXN];
int main()
{
int n;
int u,v,k;
while(scanf("%d",&n)==1)
{
init();
memset(flag,false,sizeof(flag));
for(int i=1;i<=n;i++)
{
scanf("%d:(%d)",&u,&k);
while(k--)
{
scanf("%d",&v);
flag[v]=true;
add_edge(u,v);
add_edge(v,u);
}
}
scanf("%d",&Q);
for(int i=0;i<Q;i++)
{
char ch;
cin>>ch;
scanf("%d %d)",&u,&v);
//cin>>ch;
add_query(u,v,i);
}
int root;
for(int i=1;i<=n;i++)//找到没有入度的点作为root
{
if(!flag[i])
{
root=i;
break;
}
}
LCA(root);
memset(Count_num,0,sizeof(Count_num));
for(int i=0;i<Q;i++)
{
Count_num[answer[i]]++;
}
for(int i=1;i<=n;i++)
{
if(Count_num[i]>0)
{
printf("%d:%d\n",i,Count_num[i]);
}
}
}
// getchar();getchar();
return 0;
} /*
5
5:(3) 1 4 2
1:(0)
4:(0)
2:(1) 3
3:(0)
6
(1 5) (1 4) (4 2) (2 3) (1 3) (4 3)
*/

2.带边权的Targan离线算法

http://acm.hdu.edu.cn/showproblem.php?pid=2586

#include<bits/stdc++.h>
using namespace std;
#define ll long long const int MAXN=40010;
const int MAXQ=40010; int n;
//并查集部分
int F[MAXN];//初始为-1
int find(int x)
{
if(F[x]==-1)return x;
return F[x]=find(F[x]);
} int bing(int u,int v)
{
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
F[t1]=t2;
}
} //建图部分
bool vis[MAXN];
int ancestor[MAXN];
struct Edge
{
int to,next;
int val;//每条边的权重
}edge[MAXN<<2];
int head[MAXN],tot;//head初始为-1 void add_edge(int u,int v,int val)
{
edge[tot].next=head[u];
edge[tot].to=v;
edge[tot].val=val;
head[u]=tot++;
// edge[tot].next=head[v];
// edge[tot].to=u;
// edge[tot].val=val;
// head[v]=tot++;
}
int dist[MAXN];
bool flag[MAXN];
//查询部分
struct Query
{
int q,next;
int index;//查询标号
}query[MAXQ<<1];
int answer[MAXQ];//存储每个查询的结果
int h[MAXQ];
int tt;
int Q;
void add_query(int u,int v,int index)
{
query[tt].next=h[u];
query[tt].q=v;
query[tt].index=index;
h[u]=tt++;
query[tt].next=h[v];
query[tt].q=u;
query[tt].index=index;
h[v]=tt++;
} //LCA部分
void init()
{
tot=0;
memset(F,-1,sizeof(F));
memset(vis,false,sizeof(vis));
memset(ancestor,0,sizeof(ancestor));
memset(head,-1,sizeof(head));
memset(h,-1,sizeof(h));
memset(dist,0,sizeof(dist));
memset(flag,false,sizeof(flag));
tt=0;
}
void LCA(int u,int val)
{
ancestor[u]=u;
vis[u]=true;
dist[u]=val;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
int weight=edge[i].val;
if(vis[v])continue;
LCA(v,val+weight);
bing(u,v);
ancestor[find(u)]=u;
}
for(int i=h[u];i!=-1;i=query[i].next)
{
int v=query[i].q;
if(vis[v])
{
// cout<<ancestor[find(v)]<<endl;
answer[query[i].index]=dist[v]+dist[u]-2*dist[ancestor[find(v)]];
}
}
} int root; int main()
{
int T,u,v,val;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&Q);
init();
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&val);
flag[v]=true;
add_edge(u,v,val);
add_edge(v,u,val);
}
for(int i=0;i<Q;i++)
{
scanf("%d%d",&u,&v);
add_query(u,v,i);
}
//找到没有入度的节点作为root
for(int i=1;i<=n;i++)
if(!flag[i])
{
root=i;
break;
}
LCA(root,0);
for(int i=0;i<Q;i++)
{
printf("%d\n",answer[i]);
}
} } /*
2
3 2
1 2 10
3 1 15
1 2
2 3 */

bryce1010专题训练——LCA的更多相关文章

  1. bryce1010专题训练——LCT&&树链剖分

    LCT&&树链剖分专题 参考: https://blog.csdn.net/forever_wjs/article/details/52116682

  2. bryce1010专题训练——CDQ分治

    Bryce1010模板 CDQ分治 1.与普通分治的区别 普通分治中,每一个子问题只解决它本身(可以说是封闭的) 分治中,对于划分出来的两个子问题,前一个子问题用来解决后一个子问题而不是它本身 2.试 ...

  3. bryce1010专题训练——树状数组

    Bryce1010模板 1.一维树状数组 https://vjudge.net/contest/239647#problem/A[HDU1556] #include<bits/stdc++.h& ...

  4. bryce1010专题训练——Splay树

    Prob Hint BZOJ 3323 文艺平衡树 区间翻转 BZOJ 1251 序列终结者 区间翻转,询问最值 BZOJ 1895 supermemo 区间加,翻转,剪切,询问最值.点插入,删除. ...

  5. bryce1010专题训练——划分树

    1.求区间第K大 HDU2665 Kth number /*划分树 查询区间第K大 */ #include<iostream> #include<stdio.h> #inclu ...

  6. bryce1010专题训练——线段树习题汇总

    一.区间查询,无单点更新 hdu2795 Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  7. DP专题训练之HDU 2955 Robberies

    打算专题训练下DP,做一道帖一道吧~~现在的代码风格完全变了~~大概是懒了.所以.将就着看吧~哈哈 Description The aspiring Roy the Robber has seen a ...

  8. dp专题训练

    ****************************************************************************************** 动态规划 专题训练 ...

  9. 专题训练之LCA

    推荐几个博客:https://www.cnblogs.com/JVxie/p/4854719.html Tarjan离线算法的基本思路及其算法实现 https://blog.csdn.net/shah ...

随机推荐

  1. MySQL学习笔记(四)——分组数据group by子句和having子句

    分组允许把数据分为多个逻辑组,以便对每个组进行聚集计算. 例如我们查下每个系里有多少名学生: 在使用group by 子句之前,还需要知道一些规定: 1. group by 子句可以包含任意数目的列, ...

  2. codeforces B. Ciel and Flowers 解题报告

    题目链接:http://codeforces.com/problemset/problem/322/B 题目意思:给定红花.绿花和蓝花的朵数,问组成四种花束(3朵红花,3朵绿花,3朵蓝花,1朵红花+1 ...

  3. YCSB-mapkeeper

    首先 https://github.com/brianfrankcooper/YCSB/issues/885 最终是使用ycsb-0.1.4 版本进行,这个版本自带jar包 https://githu ...

  4. 解决Exception:Could not open Hibernate Session for transaction; nested exception is java.lang.NoClassDefFoundError: org/hibernate/engine/transaction/spi/TransactionContext

    原因是配置文件中 <bean id="transactionManager" class="org.springframework.orm.hibernate4.H ...

  5. 自己实现c++中string 类

    class String { public: String(const char *str = NULL);// 普通构造函数 String(const String &other);// 拷 ...

  6. Java并发实现线程阻塞原语LockSupport

    LockSupport 和 CAS 是Java并发包中很多并发工具控制机制的基础,它们底层其实都是依赖Unsafe实现.LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. 1.Lock ...

  7. ubuntu下网络性能测试

    iperf的主要功能 TCP 测量网络带宽 报告MSS/MTU值的大小和观测值 支持TCP窗口值通过套接字缓冲 当P线程或Win32线程可用时,支持多线程.客户端与服务端支持同时多重连接 UDP 客户 ...

  8. Win10设置vs2010总是以管理员身份运行

    有的项目用vs打开后直接运行总是要求提升权限,如下图       1.第一步(这样的方式只能是先运行vs,然后再打开项目,这样才是以管理员的身份运行的.但是如果是通过sln文件的快捷方式打开的,却不是 ...

  9. 是否要从单片机转为嵌入式Linux?

    作者:嵌入式老鸟火哥 授权转载于公众号嵌入式老鸟的职场之道(ID: ict_embedded),有增加内容和修改. 最近很多童鞋投票并咨询如何从单片机转为嵌入式Linux开发.看来读者圈中做单片机,R ...

  10. SSIS 增量更新

    本文转自 http://sqlblog.com/blogs/andy_leonard/archive/2007/07/09/ssis-design-pattern-incremental-loads. ...