有一只很强的怪//给它随便起个名字好了,就叫HLJ吧
地图可以抽象成一棵树
你可以在任意节点上召唤它
你有一些士兵,每个士兵也在一个节点上
士兵有射程,只能攻击树上路径距离不超过W的点//ps:住手,这根本不是平面图好吧
HLJ出现在节点上的时候,只会被攻击到一次,当HLJ与士兵在同一个节点上的时候,默认士兵的攻击先发动
HLJ有仇恨,从最后一次伤害来源中任取一个
当然了,士兵也可以选择不进行攻击
特别的,你并不清楚HLJ的具体血量
因此,要求对于任意血量N,你都能保证击败HLJ
求最小射程W,题目特性(存在两个士兵不在同一个节点上)保证有解
多组询问
首先,显然的,肯定是在一条边上耗死
即求
我们考虑虚树求解
先二分转判定看看,以下均为描述check(k)
考虑一条边在某个关键点对中的一个点x到LCA的路径上 描述为一条son到f的边
对于son点(以下称为标记点)若满足dist(x,f)<=k且存在一个son子树外的点到son的dist<=k
那么答案合法
建出虚树,倍增找出每个关键点最远可标记的点,考虑对这一条链上的点打标记,记为mark[x]
在建虚树的时候,还要记录每个点到其父亲最底端的节点
标记更新的时候分两种情况,标记是否在链顶的上端,讨论一下更新
据说分是否超过一百选择暴力统计点对或树形DP能过?
匀一匀大概是O(100^2*(M/100)*log(n)+(M/100)*n) M=sigma K(询问点数)=2e5 N=1e5
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
const int N=2e5+10,M=N<<1,INF=0x3f7f7f7f,LOG=20;
namespace IO{
const int ios=1<<17;
char R[ios],P[ios],*Rc=R,*RB=R,*Pc=P;
const char*PB=P+ios;
int stk[50],tp=0,pass;
inline void flush(){fwrite(P,1,Pc-P,stdout);Pc=P;}
inline int gec(){return(Rc==RB&&(RB=(Rc=R)+fread(R,1,ios,stdin),Rc==RB))?EOF:*Rc++;}
inline void puc(const char&c){if(Pc==PB)flush();*(Pc++)=c;}
template<typename Tp>inline int read(Tp&A){
static int c,sg;c=gec();sg=0;A=0;
while(!isdigit(c)&&c!=EOF)sg|=(c=='-'),c=gec();
if(c==EOF)return EOF;
while(isdigit(c))A=(A<<3)+(A<<1)+(c^'0'),c=gec();
return 0;
}
inline int read(){return read(pass),pass;}
template<typename Tp>inline void print(Tp A){
if(A<0)puc('-');
if(!A)puc('0');
for(int Q,P;A;A=Q)Q=A/10,P=A-10*Q,stk[++tp]=P^'0';
while(stk[tp])puc(stk[tp--]);
}
}
using IO::gec;using IO::puc;using IO::read;using IO::print;using IO::flush;
int s[N][LOG];
int fr[N],nx[M],to[M],w[M],E;
int fir[N],nex[M],toe[M],we[M],ED,q[N],que[N];
int dfn[N],DFN,dep[N]={INF},deep[N],mark[N],mind[N];
int n,m,res,K,key,Min_L,flag,ques;
bool vis[N],has[N];
inline void adde(int x,int y,int W){
to[++E]=y;w[E]=W;nx[E]=fr[x];fr[x]=E;
}
inline int skp(int x,int ss){
for(int i=LOG-1;~i;i--)
if(s[x][i]>1&&dep[s[x][i]]>ss)
x=s[x][i];
return x;
}
inline void link(int x,int y){
toe[++ED]=y;we[ED]=dep[y]-dep[x];nex[ED]=fir[x];fir[x]=ED;
mind[y]=dep[skp(y,dep[x])];
}
inline int depth_cmp(int a,int b){return dep[a]<dep[b]?a:b;}
inline bool dfn_cmp(int a,int b){return dfn[a]<dfn[b];}
void dfs(int x,int f){
dfn[x]=++DFN;s[x][0]=f;
for(int i=fr[x];i;i=nx[i])
if(to[i]!=f){
deep[to[i]]=deep[x]+1;
dep[to[i]]=dep[x]+w[i];
dfs(to[i],x);
}
}
inline int LCA(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int S=deep[x]-deep[y];
for(int i=0;i<LOG;i++,S>>=1)
if(S&1)x=s[x][i];
if(x==y)return x;
for(int i=LOG-1;~i;i--)
if(s[x][i]!=s[y][i])
x=s[x][i],y=s[y][i];
return s[x][0];
}
inline int skip(int x,int ss){
int lim=dep[x]-ss;
if(dep[s[x][0]]<lim)return -1;
for(int i=LOG-1;~i;i--)
if(s[x][i]>1&&dep[s[s[x][i]][0]]>=lim)
x=s[x][i];
return x;
}
int DPrun(int x){
int A=has[x]?0:INF,B=INF;
for(int i=fir[x];i;i=nex[i]){
int tmp=DPrun(toe[i])+we[i];
if(tmp<A)B=A,A=tmp;
else if(tmp<B)B=tmp;
}
Min_L=min(Min_L,A+B);
return A;
}
struct data{
data(int a,int c,int d):a(a),c(c),d(d){}
int a,c,d;
};
data run(int x){
int A=has[x]?0:INF,C=INF,D=mark[x]?mark[x]:INF;
for(int i=fir[x];i;i=nex[i]){
data s=run(toe[i]);
int tmp=s.a+we[i],temp=s.c+we[i],ter=s.d;
if(C+tmp<=key)flag=1;
if(A+temp<=key)flag=1;
if(tmp<A)A=tmp;
if(temp<C)C=temp;
if(ter<D)D=ter;
}
if(D<=mind[x])C=mind[x]-dep[x];
else C=min(C,D-dep[x]);
return data(A,C,D);
}
int stk[N<<1],top;
inline void build(int m){
sort(q+1,q+m+1,dfn_cmp);ques=0;
int top=1;stk[1]=1;que[++ques]=1;
for(int i=1;i<=m;i++){
if(q[i]==q[i-1])continue;
int S=LCA(stk[top],q[i]);
if(S!=stk[top]){
while(dfn[stk[top-1]]>dfn[S]&&top>1)
link(stk[top-1],stk[top]),top--;
if(stk[top-1]==S&&top>1)
link(stk[top-1],stk[top]),top--;
else
if(top>1)link(S,stk[top]),stk[top]=S,que[++ques]=S;
}
stk[++top]=q[i],que[++ques]=q[i];
}
while(top>1)link(stk[top-1],stk[top]),top--;
}
bool check(int step){
int tot=K;
for(int i=1;i<=K;i++){
int v=skip(q[i],step);
if(v!=-1)mark[q[i]]=dep[v];
}
key=step;flag=0;
run(1);
for(int i=1;i<=K;i++)mark[q[i]]=0;
return flag;
}
int solve(){
build(K);
Min_L=INF;DPrun(1);
int l=Min_L>>1,r=Min_L;
while(l<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}return l;
}
int main(){
freopen("laqiang.in","r",stdin);
freopen("laqiang.out","w",stdout);
read(n);read(m);q[0]=1;
for(int i=1,u,v,W;i<n;i++){
read(u);read(v);read(W);
adde(u,v,W);adde(v,u,W);
}
dfs(1,0);
for(int i=1;i<LOG;i++)
for(int j=1;j<=n;j++)
s[j][i]=s[s[j][i-1]][i-1];
for(int i=1;i<=m;i++){
int cur=0;
read(K);res=INF;
for(int j=1;j<=K;j++)read(q[j]),has[q[j]]=1;
printf("%d\n",solve());
for(int j=1;j<=K;j++)has[q[j]]=0;
for(int i=1;i<=ques;i++)fir[que[i]]=0;
}
return 0;
}