bzoj 2286 消耗战
题目大意:
一棵树 Q次询问 每次询问给K个点 求把些点都与根断开的最小代价
思路:
学习了一波虚树
记录一下每个点到根的路径上边权的最小值 dp+虚树
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 500100 12 #define Fill(a,x) memset(a,x,sizeof(a)) 13 #define to1 g1.to[i] 14 #define to2 g2.to[i] 15 using namespace std; 16 inline int read() 17 { 18 int x=0,f=1;char ch=getchar(); 19 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 20 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 21 return x*f; 22 } 23 int n,f[MAXN][24],dep[MAXN],hsh[MAXN]; 24 int st[MAXN],top,tot,g[MAXN];; 25 ll mn[MAXN]; 26 struct graph 27 { 28 int fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt; 29 graph() {Fill(fst,0);cnt=0;} 30 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 31 }g1,g2; 32 bool cmp(const int &a,const int &b) {return hsh[a]<hsh[b];} 33 void dfs(int x,int fa) 34 { 35 hsh[x]=++tot; 36 for(int i=1;(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1]; 37 for(int i=g1.fst[x];i;i=g1.nxt[i]) 38 if(to1!=fa) {dep[to1]=dep[x]+1,f[to1][0]=x,mn[to1]=min((ll)g1.val[i],mn[x]);dfs(to1,x);} 39 } 40 int lca(int u,int v) 41 { 42 if(dep[u]<dep[v]) swap(u,v);int t=dep[u]-dep[v]; 43 for(int i=23;~i;i--) if((1<<i)&t) u=f[u][i]; 44 if(u==v) return u; 45 for(int i=23;~i;i--) 46 if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; 47 return f[u][0]; 48 } 49 void ins(int x) 50 { 51 if(top==1) {st[++top]=x;return ;} 52 int y=lca(x,st[top]); 53 if(st[top]==y) return ; 54 while(top>1&&hsh[st[top-1]]>=hsh[y]) g2.add(st[top-1],st[top],0),top--; 55 if(y!=st[top]) {g2.add(y,st[top],0);st[top]=y;}st[++top]=x; 56 } 57 ll dp(int x) 58 { 59 ll sum=0; 60 for(int i=g2.fst[x];i;i=g2.nxt[i]) sum+=dp(to2); 61 g2.fst[x]=0; 62 return min(sum==0LL?2139062143000000000LL:sum,(ll)mn[x]); 63 } 64 int main() 65 { 66 n=read();int a,b,c; 67 for(int i=1;i<n;i++) {a=read(),b=read(),c=read();g1.add(a,b,c);g1.add(b,a,c);} 68 Fill(mn,127);dfs(1,0);int m=read();mn[1]=inf*100000LL; 69 while(m--) 70 { 71 a=read();for(int i=1;i<=a;i++) g[i]=read(); 72 sort(g+1,g+a+1,cmp);st[top=1]=1,g2.cnt=0; 73 for(int i=1;i<=a;i++) ins(g[i]); 74 while(top) g2.add(st[top-1],st[top],0),top--; 75 printf("%lld\n",dp(1)); 76 } 77 }