Tarjan 缩点
题意:给一个有向点权图,重复经过一个点只算一次点权,求一条路径使得路径上的点权和最大。’
思路:将强连通分量缩点,变成一个DAG,拓扑排序求最长路
时间复杂度O(n)
#include<bits/stdc++.h>
using namespace std;
#define next Next
const int N=1e5+7,M=1e5+7;
struct Graph{
struct Edge{
int u,v,next;
}e[M];
struct Information{
//存重新建边后新节点的各种信息
int size,val,in,out;//大小,点权,入度,出度
Information():val(0),in(0),out(0){
}
}vertex[N];
int n,edit_n,m,dfn[N],low[N],vis[N],head[N],tot,cnt,belong[N],id[N],value[N];
//dfn时间戳, low能追溯到的最早的栈中节点的次序号, vis是否在栈中
//belong属于哪个强连通分量, id缩点后的新编号
stack<int>st;
int sum[N],ans;//路径上的点权
void clear(){
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++)belong[i]=i;
tot=cnt=edit_n=0;
}
void add(int u,int v){
e[++tot]=Edge{
u,v,head[u]};head[u]=tot;}
void Tarjan(int u){
//找强连通分量
dfn[u]=low[u]=++cnt;
st.push(u);
vis[u]=1;
for(int i=head[u];i;i=e[i].next){
if(!dfn[e[i].v]){
Tarjan(e[i].v);
low[u]=min(low[u],low[e[i].v]);
}else{
if(vis[e[i].v])
low[u]=min(low[u],dfn[e[i].v]);
}
}
int now=0;
if(dfn[u]==low[u]){
id[u]=++edit_n;//给当前强连通分量新的编号
while(now!=u){
now=st.top();st.pop();
vertex[id[u]].size++;
vertex[id[u]].val+=value[now];
vis[now]=0;
belong[now]=u;
}
}
}
void Rebuild(){
//重新建边
memset(head,0,sizeof(head));
tot=0;
for(int i=1;i<=m;i++){
int u=belong[e[i].u],v=belong[e[i].v];
if(u!=v){
add(id[u],id[v]);
vertex[id[u]].out++;
vertex[id[v]].in++;
}
}
swap(n,edit_n); m=tot;//新的点数和边数
}
void Topo(){
//拓扑排序
queue<int>q;
for(int i=1;i<=n;i++)
if(vertex[i].in==0){
q.push(i);
sum[i]=vertex[i].val;
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u],v;i;i=e[i].next){
v=e[i].v;
sum[v]=max(sum[v],sum[u]+vertex[v].val);
vertex[v].in--;
if(vertex[v].in==0)q.push(v);
}
}
}
void Solve(){
/* 缩点 */
for(int i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
Rebuild();
/* 拓扑排序求最大路径点权和 */
Topo();
for(int i=1;i<=n;i++)ans=max(ans,sum[i]);
}
}G;
int main(){
cin>>G.n>>G.m;
G.clear();
for(int i=1;i<=G.n;i++)scanf("%d",&G.value[i]);
for(int i=1,u,v;i<=G.m;i++){
scanf("%d%d",&u,&v);
G.add(u,v);
}
G.Solve();//缩点
printf("%d",G.ans);
}
倍增LCA
O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define next Next
const int N=1e5+7;
struct Tree{
struct Edge{
int u,v,next;}e[N<<1];
int n,root,fa[N][30],dep[N],head[N],tot;
void clear(){
memset(head,0,sizeof(head));
memset(dep,-1,sizeof(dep));
tot=0;
}
void add(int u,int v){
e[++tot]=Edge{
u,v,head[u]};head[u]=tot;}
void addedge(int u,int v){
add(u,v);add(v,u);}
void dfs(int u,int pre=0){
dep[u]=dep[pre]+1;
fa[u][0]=pre;
for(int i=1;(1<<i)<=dep[u];i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].next)
if(e[i].v!=pre)dfs(e[i].v,u);
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=20;i>=0;i--){
if(dep[u]>=dep[v]+(1<<i))
u=fa[u][i];
}
if(u==v)return u;
for(int i=20;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
}T;
int main(){
T.clear();
int q;
cin>>T.n>>q>>T.root;
for(int i=1,u,v;i<T.n;i++){
scanf("%d%d",&u,&v);
T.addedge(u,v);
}
T.dfs(T.root);
for(int i=1,u,v;i<=q;i++){
scanf("%d%d",&u,&v);
printf("%d\n",T.LCA(u,v));
}
}