luogu P2495 [SDOI2011]消耗战
背景:
我好菜(连虚树都不会,虽然曾经比赛时出现过,但现在才学)。
看了几个某中学同级认识的大佬的,感觉被爆了。
感觉自己好菜
题意:
一棵树,多组询问,每一次选出个点,使得无法到这个点所删边的权值和的最小值。
思路:
虚树的入门题。
参考:https://www.cnblogs.com/zwfymqz/p/9175152.html 。
虚树:只用保留所必需的点(被询问到的点和它们的)。
构建过程:
但是我认为那个大佬的并不是序,而是重链剖分的顺序(树剖的顺序),然后代码就跟他不同了。
最后写个显然的即可。
其实细节挺复杂的。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
struct node1{int x,y,next;LL z;} a[600010];
struct node2{int x,y,next;}b[600010];
int lasta[600010],lastb[600010],d[600010],id[600010],f[600010][25],sta[600010],dep[600010];
LL mi[600010],dp[600010];
int n,m,k,lena=0,lenb=0;
void ins_a(int x,int y,LL z)
{
a[++lena]=(node1){x,y,lasta[x],z}; lasta[x]=lena;
}
void ins_b(int x,int y)
{
b[++lenb]=(node2){x,y,lastb[x]}; lastb[x]=lenb;
}
void init()
{
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
}
int op=0;
void dfs(int x,int fa)
{
id[x]=++op;
for(int i=lasta[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
f[y][0]=x;
mi[y]=min(mi[x],a[i].z);
dep[y]=dep[x]+1;
dfs(y,x);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--)
if(dep[y]<=dep[f[x][i]]) x=f[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int top;
void build(int x)
{
int LCA=lca(x,sta[top]);
if(sta[top]!=LCA)
{
while(id[sta[--top]]>id[LCA]) ins_b(sta[top],sta[top+1]),ins_b(sta[top+1],sta[top]);
ins_b(LCA,sta[top+1]),ins_b(sta[top+1],LCA);
if(LCA!=sta[top]) sta[++top]=LCA;
}
sta[++top]=x;
}
void solve(int x,int fa)
{
dp[x]=mi[x];
LL sum=0;
for(int i=lastb[x];i;i=b[i].next)
{
int y=b[i].y;
if(y==fa) continue;
solve(y,x);
sum+=dp[y];
}
lastb[x]=0;
if(sum) dp[x]=min(sum,(LL)mi[x]);
}
bool cmp(int x,int y)
{
return id[x]<id[y];
}
int main()
{
int x,y;
LL z;
scanf("%d",&n);
mi[1]=(1ll<<60);
for(int i=1;i<n;i++)
{
scanf("%d %d %lld",&x,&y,&z);
ins_a(x,y,z),ins_a(y,x,z);
}
dep[1]=1;
dfs(1,0);
init();
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&k);
for(int j=1;j<=k;j++)
scanf("%d",&d[j]);
sort(d+1,d+k+1,cmp);
int op=1;
for(int j=2;j<=k;j++)
if(lca(d[op],d[j])!=d[op]) d[++op]=d[j];
k=op;
sta[top=1]=1;
lenb=0;
for(int j=1;j<=k;j++)
build(d[j]);
top--;
while(top)
ins_b(sta[top],sta[top+1]),ins_b(sta[top+1],sta[top]),top--;
solve(1,0);
printf("%lld\n",dp[1]);
}
}