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 }
View Code

 

posted @ 2018-11-21 12:50  jack_yyc  阅读(133)  评论(0编辑  收藏  举报