这个题当时比赛的时候算了下,lca+暴力会超时。后来去网上搜题解。他们说可以a 可能是数据不强吧。
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#define max 100010
#define maxl 27
using namespace std;
typedef struct
{
int from,to,w;
}edge;
//这个结构体用来存储边
vector<int>zz[max];
vector<edge>edges;
vector<int> G[max];
//保存边的数组
int grand[max][maxl],gw[max][maxl];//x向上跳2^i次方的节点,x到他上面祖先2^i次方
int depth[max];//深度
int in[max];
int n,m,N;
void addedge(int x,int y,int w)//把边保存起来的函数
{
edge a={x,y,w},b={y,x,w};
edges.push_back(a);
edges.push_back(b);
G[x].push_back(edges.size()-2);
G[y].push_back(edges.size()-1);
}
void dfs(int x)//dfs建图
{
for(int i=1;i<=N;i++)//第一个几点就全部都是0咯,第二个节点就有变化了,不理解
{
grand[x][i]=grand[grand[x][i-1]][i-1];
gw[x][i]=gw[x][i-1]+gw[grand[x][i-1]][i-1];
// if(grand[x][i]==0) break;
}
for(int i=0;i<G[x].size();i++)
{ edge e = edges[G[x][i]];
if(e.to!=grand[x][0])//这里我们保存的是双向边所以与他相连的边不是他父
{
depth[e.to]=depth[x]+1;//他儿子的深度等于他爸爸的加1
grand[e.to][0]=x;//与x相连那个节点的父亲等于x
gw[e.to][0]=e.w;//与x相连那个节点的距离等于这条边的距离
dfs(e.to);//深搜往下面建
}
}
}
void Init(){
//n为节点个数
N = floor(log(n + 0.0) / log(2.0));//最多能跳的2^i祖先
//根结点的祖先不存在,用-1表示
memset(grand,0,sizeof(grand));
memset(gw,0,sizeof(gw));
memset(depth,-1,sizeof(depth));
for(int i=1;i<=n;i++)if(!in[i]){depth[i]=0;dfs(i); break;}//以1为根节点建树
}
int lca(int a,int b)
{ if(depth[a] > depth[b]) swap(a, b);//保证a在b上面,便于计算
int ans = 0;
for(int i = N; i >= 0; i--) //类似于二进制拆分,从大到小尝试
if(depth[a] < depth[b] && depth[grand[b][i]] >= depth[a])//a在b下面且b向
ans +=gw[b][i], b=grand[b][i];//先把深度较大的b往上跳
for(int j=N;j>=0;j--)//在同一高度了,他们一起向上跳,跳他们不相同节点,当全都
{
if(grand[a][j]!=grand[b][j])
{ ans+=gw[a][j];
ans+=gw[b][j];
a=grand[a][j];
b=grand[b][j];
}
}
if(a!=b)//a等于b的情况就是上面土色字体的那种情况
{
ans+=gw[a][0],ans+=gw[b][0];
a=grand[a][0];
b=grand[b][0];
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while( t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
G[i].clear();
}
for(int i=1;i<=m;i++)
{
zz[i].clear();
}
edges.clear();
memset(in,0,sizeof(in));
for(int i=1;i<n;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addedge(x,y,w);
in[y]++;
}
Init();
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
scanf("%d",&y);
zz[i].push_back(y);
}
}
// printf("%d\n",lca(1,1));
int q;
scanf("%d",&q);
int s,e;
for(int i=1;i<=q;i++)
{
scanf("%d %d",&s,&e);
int min=999999999;
for(int j=0;j<zz[s].size();j++)
{
for(int k=0;k<zz[e].size();k++)
{
int mm=lca(zz[s][j],zz[e][k]);
if(mm<min) min=mm;
}
}
printf("%d\n",min);
}
}
}