Tarjan算法(离线算法)模板
#include<cstdio>
#include<string.h>
using namespace std;
int n,head[10010],k,x,y,d[10010],f[10010],ans[10010],num[10010];
bool visit[10010];
struct point{
int to;
int next;
}edge[10010];
void addedge(int a,int b){
edge[k].to=b;
edge[k].next=head[a];
head[a]=k++;
}
int find(int u){
int s;
for(s=u;f[s]!=s;s=f[s]); //s为根节点
while(s!=u){
int tmp=f[u];
f[u]=s;
u=tmp;
}
return s;
}
void Union(int a,int b){
int p=find(a);
int q=find(b);
if(p==q)
return;
if(num[p]<=num[q]){
f[p]=q;
num[q]+=num[p];
}
else{
f[q]=p;
num[p]+=num[q];
}
}
void LCA(int u){
int i;
ans[u]=u;
for(i=head[u];i!=-1;i=edge[i].next){
LCA(edge[i].to);
Union(u,edge[i].to);
ans[find(u)]=u; //有可能u并不是新树的根,所以要加这句
}
visit[u]=1;
if(u==x){
if(visit[y])
printf("%d\n",ans[find(y)]);
}
else if(u==y){
if(visit[x])
printf("%d\n",ans[find(x)]);
}
}
int main(){
int T,t,i,j;
scanf("%d",&T);
for(t=1;t<=T;t++){
scanf("%d",&n);
k=0;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
memset(visit,0,sizeof(visit));
for(i=1;i<=n;i++)
f[i]=i,num[i]=1;
for(i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
addedge(u,v);
d[v]++;
}
scanf("%d %d",&x,&y);
for(j=1;j<=n;j++)
if(!d[j])
LCA(j);
}
}
LCA转化为RMQ(在线算法)
#include<cstdio>
#include<string.h>
#include<math.h>
using namespace std;
int n,head[1000],k,ans[1000],num[1000],d[1000];
int h[1000*2],e[1000*2],f[1000],cnt;
bool visit[1000];
int dp[1000*2][12]; //数组不要开小了
int sign[1000];
struct point{
int to;
int next;
}edge[1000];
void addedge(int a,int b){
edge[k].to=b;
edge[k].next=head[a];
head[a]=k++;
}
void dfs(int u,int hh){
e[++cnt]=u;
h[cnt]=hh;
if(!visit[u]){
f[u]=cnt;
visit[u]=1;
}
for(int i=head[u];i!=0;i=edge[i].next){
dfs(edge[i].to,hh+1);
e[++cnt]=u;
h[cnt]=hh;
}
}
void init(){
int i,j;
for(i=1;i<=cnt;i++)
dp[i][0]=i;
for(i=1;(1<<i)<=cnt;i++){
for(j=1;j+(1<<i)-1<=cnt;j++){
if(h[dp[j][i-1]]<h[dp[j+(1<<(i-1))][i-1]])
dp[j][i]=dp[j][i-1];
else
dp[j][i]=dp[j+(1<<(i-1))][i-1];
}
}
}
int RMQ(int s,int t){
if( s>t){
int tt=t;
t=s;
s=tt;
}
int kk=(int)(log(double(t-s+1)*1.0)/log(2.0));
return h[dp[s][kk]]<h[dp[t-(1<<kk)+1][kk]]?dp[s][kk]:dp[t-(1<<kk)+1][kk];
}
int main(){
int i,j;
while(scanf("%d",&n)!=EOF){
memset(sign,0,sizeof(sign));
memset(head,0,sizeof(head));
memset(d,0,sizeof(d));
memset(visit,0,sizeof(visit));
k=1;cnt=0;
for(i=1;i<=n;i++){
int tem;
scanf("%d",&tem);
while(getchar()!='(');
int sum;
scanf("%d",&sum);
while(getchar()!=')');
for(j=1;j<=sum;j++){
int tt;
scanf("%d",&tt);
addedge(tem,tt);
d[tt]++;
}
}
for(i=1;i<=n;i++)
if(!d[i])
break;
dfs(i,0);
int m;
scanf("%d",&m);
init();
for(i=1;i<=m;i++){
while(getchar()!='(');
int u,v;
scanf("%d%d",&u,&v);
int pos=RMQ(f[u],f[v]);
sign[e[pos]]++;
while(getchar()!=')');
}
for(i=1;i<=n;i++)
if(sign[i]){
printf("%d:%d\n",i,sign[i]);
}
}
}
RMQ还可以先转化LCA(用笛卡尔树),再转化为±1RMQ问题,有o(n)-o(1)的在线算法。(这个还没学)