虚树 模板...
虚树的话,就是把有用的的结点从树中提取出来,从而不会超时的一种东西
先把点都读入进来
按照dfs序排序
在把相邻的点的LCA加入
再按照dfs序排序
然后用栈维护一条祖先后代链
然后在维护过程中退栈的时候加边就行了
bzoj_3611大工程
虚树+dp
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; char rea=0; inline void read(int &x) { x=0; while(rea<'0'||rea>'9') rea=getchar(); while(rea>='0'&&rea<='9') x=x*10+rea-'0',rea=getchar(); } const int N=1000006; const ll Inf=1e12; int first[N],nt[N<<1],ver[N<<1],e; inline void addbian(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,m; int timer,vis[N],t[N],con,root; int isk[N]; int fa[N],dep[N],st[N][30],maxk,dfn[N],tim,qi[N],ho[N]; void dfs(int x) { dfn[x]=++tim; qi[x]=tim; int i; for(i=first[x];i!=-1;i=nt[i]) { if(ver[i]==fa[x]) continue; fa[ver[i]]=x; dep[ver[i]]=dep[x]+1; dfs(ver[i]); } ho[x]=tim; } void ST() { while((1<<maxk)<=n) ++maxk; --maxk; int i,j; mem(st,-1); for(i=1;i<=n;++i) st[i][0]=fa[i]; for(j=1;(1<<j)<=n;++j) for(i=1;i<=n;++i) if(st[i][j-1]!=-1) st[i][j]=st[st[i][j-1]][j-1]; } int LCA(int x,int y) { if(dep[x]<dep[y]) x^=y,y^=x,x^=y; int i; for(i=maxk;~i;--i) if(dep[x]-(1<<i)>=dep[y]) x=st[x][i]; if(x==y) return x; for(i=maxk;~i;--i) if(st[x][i]!=-1&&st[x][i]!=st[y][i]) x=st[x][i],y=st[y][i]; return fa[x]; } struct T0v0T { int first[N],nt[N<<1],ver[N<<1],e; void clear() { int i; e=0; for(i=1;i<=con;++i) first[t[i]]=-1; } inline void addbian(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } }h; int zhan[N],he; bool cmp(int a,int b) { return dfn[a]<dfn[b]; } ll mndep[N],mxdep[N],mnan[N],mxan[N],size[N]; ll sum[N],ansum; void dp(int x,int prr) { size[x]=0; if(isk[x]==timer) size[x]=1; mndep[x]=Inf; if(isk[x]==timer) mndep[x]=dep[x]; mxdep[x]=0; if(isk[x]==timer) mxdep[x]=dep[x]; mnan[x]=Inf; mxan[x]=0; sum[x]=0; if(isk[x]==timer) sum[x]=dep[x]; int i,te; ll tt=0,mn=Inf,mn2=Inf,mx=0,mx2=0; for(i=h.first[x];i!=-1;i=h.nt[i]) if(h.ver[i]!=prr) { dp(h.ver[i],x); sum[x]+=sum[h.ver[i]]; size[x]+=size[h.ver[i]]; if(mn>mndep[h.ver[i]]) { mn2=mn; mn=mndep[h.ver[i]]; } else if(mn2>mndep[h.ver[i]]) mn2=mndep[h.ver[i]]; if(mx<mxdep[h.ver[i]]) { mx2=mx; mx=mxdep[h.ver[i]]; } else if(mx2<mxdep[h.ver[i]]) mx2=mxdep[h.ver[i]]; } if(isk[x]==timer) { tt+=1LL*(size[x]-1)*dep[x]; tt+=1LL*(1)*(sum[x]-dep[x]); tt-=1LL*dep[x]*2*(1)*(size[x]-1); } for(i=h.first[x];i!=-1;i=h.nt[i]) if(h.ver[i]!=prr) { tt+=1LL*(size[x]-size[h.ver[i]])*sum[h.ver[i]]; tt+=1LL*size[h.ver[i]]*(sum[x]-sum[h.ver[i]]); tt-=1LL*dep[x]*2*(size[h.ver[i]])*(size[x]-size[h.ver[i]]); } ansum+=tt/2; if(isk[x]==timer) { if(mn>dep[x]) { mn2=mn; mn=dep[x]; } else if(mn2>dep[x]) mn2=dep[x]; if(mx<dep[x]) { mx2=mx; mx=dep[x]; } else if(mx2<dep[x]) mx2=dep[x]; } mndep[x]=mn; mxdep[x]=mx; mnan[x]=mn+mn2-2*dep[x]; mxan[x]=mx+mx2-dep[x]*2; } void work() { rint i,j; int ycon=con,tt; sort(t+1,t+1+con,cmp); for(i=1;i<ycon;++i) { tt=LCA(t[i],t[i+1]); if(vis[tt]!=timer) t[++con]=tt,vis[tt]=timer; } sort(t+1,t+1+con,cmp); he=0; h.clear(); for(i=1;i<=con;++i) { if(!he) zhan[++he]=t[i]; else { while(he>1&&!(qi[t[i]]>=qi[zhan[he]]&&ho[t[i]]<=ho[zhan[he]])) h.addbian(zhan[he-1],zhan[he]),--he; zhan[++he]=t[i]; } } while(he>1) h.addbian(zhan[he-1],zhan[he]),--he; root=zhan[1]; ansum=0; dp(root,-1); ll mn=Inf,mx=0; for(i=1;i<=con;++i) { if(mn>mnan[t[i]]) mn=mnan[t[i]]; if(mx<mxan[t[i]]) mx=mxan[t[i]]; } printf("%lld %lld %lld\n",ansum,mn,mx); } int main(){ //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); rint i,j; int tin1,tin2,Q,K,tin; mem(first,-1); read(n); for(i=1;i<n;++i) { read(tin1); read(tin2); addbian(tin1,tin2); addbian(tin2,tin1); } fa[1]=-1; dfs(1); ST(); read(Q); for(i=1;i<=Q;++i) { read(K); ++timer; con=0; for(j=1;j<=K;++j) ++con,read(t[con]),vis[t[con]]=timer,isk[t[con]]=timer; if(K<2) { printf("0 0 0\n"); continue; } work(); } }
bzoj_2286消耗战
虚树+dp
最小值要用倍增,树链剖分会T
开long long
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; char rea=0; inline void read(int &x) { x=0; while(rea<'0'||rea>'9') rea=getchar(); while(rea>='0'&&rea<='9') x=x*10+rea-'0',rea=getchar(); } const int N=250006; const int Inf=2e9; const ll llInf=1e15; int first[N],w[N<<1],nt[N<<1],ver[N<<1],e; void addbian(int u,int v,int _w) { ver[e]=v; w[e]=_w; nt[e]=first[u]; first[u]=e++; } int n,m,K; int maxk; int t[N],con; int zhan[N],he; int vis[N],timer; int fa[N],dep[N],v[N]; int dfn[N],tim,qi[N],ho[N]; int st[N][30],mn[N][30]; void dfs1(int x) { dfn[x]=qi[x]=++tim; int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { fa[ver[i]]=x; dep[ver[i]]=dep[x]+1; v[ver[i]]=w[i]; dfs1(ver[i]); } ho[x]=tim; } void ST() { while((1<<maxk)<=n) ++maxk; --maxk; rint i,j; mem(st,-1); mem(mn,0x7f); for(i=1;i<=n;++i) st[i][0]=fa[i],mn[i][0]=v[i]; for(j=1;(1<<j)<=n;++j) for(i=1;i<=n;++i) if(st[i][j-1]!=-1) st[i][j]=st[st[i][j-1]][j-1], mn[i][j]=min(mn[i][j-1],mn[st[i][j-1]][j-1]); } int LCA(int x,int y) { int i; if(dep[x]<dep[y]) x^=y,y^=x,x^=y; for(i=maxk;~i;--i) if(dep[x]-(1<<i)>=dep[y]) x=st[x][i]; if(x==y) return x; for(i=maxk;~i;--i) if(st[x][i]!=-1&&st[x][i]!=st[y][i]) x=st[x][i],y=st[y][i]; return fa[x]; } int MN(int x,int y) { int i,an=Inf; if(dep[x]<dep[y]) x^=y,y^=x,x^=y; for(i=maxk;~i;--i) if(dep[x]-(1<<i)>=dep[y]) { if(an>mn[x][i]) an=mn[x][i]; x=st[x][i]; } if(x==y) return an; for(i=maxk;~i;--i) if(st[x][i]!=-1&&st[x][i]!=st[y][i]) { if(an>mn[x][i]) an=mn[x][i]; if(an>mn[y][i]) an=mn[y][i]; x=st[x][i],y=st[y][i]; } if(an>mn[x][0]) an=mn[x][0]; if(an>mn[y][0]) an=mn[y][0]; return an; } struct T0x0T { int first[N],w[N<<1],nt[N<<1],ver[N<<1],e; void clear() { int i; e=0; for(i=1;i<=con;++i) first[t[i]]=-1; } void addbian(int u,int v,int _w) { ver[e]=v; w[e]=_w; nt[e]=first[u]; first[u]=e++; } }h; ll f[N]; int isk[N],sz[N]; void dp(int x) { //printf("x=%d\n",x); f[x]=0; int i; for(i=h.first[x];i!=-1;i=h.nt[i]) { //printf("x=%d ver=%d w=%d\n",x,h.ver[i],h.w[i]); dp(h.ver[i]); if(isk[h.ver[i]]==timer) f[x]+=h.w[i]; else f[x]+=min((ll)h.w[i],f[h.ver[i]]); } } bool cmp(int a,int b) { return dfn[a]<dfn[b]; } void work() { sort(t+1,t+1+con,cmp); rint i; int tt,t1; tt=con; for(i=1;i<tt;++i) { t1=LCA(t[i],t[i+1]); if(vis[t1]!=timer) t[++con]=t1,vis[t1]=timer; } sort(t+1,t+1+con,cmp); he=0; h.clear(); for(i=1;i<=con;++i) { if(!he) zhan[++he]=t[i]; else { while( he>1 && (!(qi[zhan[he]]<=qi[t[i]]&&ho[zhan[he]]>=ho[t[i]])) ) h.addbian(zhan[he-1],zhan[he],MN(zhan[he-1],zhan[he])),--he; zhan[++he]=t[i]; } } while(he>1) h.addbian(zhan[he-1],zhan[he],MN(zhan[he-1],zhan[he])),--he; /* printf("\n"); for(i=1;i<=con;++i) printf("%d ",t[i]); printf("\n");*/ dp(1); printf("%lld\n",f[1]); } int main(){ //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); rint i,j; int tin1,tin2,tin3; mem(first,-1); read(n); for(i=1;i<n;++i) { read(tin1); read(tin2); read(tin3); addbian(tin1,tin2,tin3); addbian(tin2,tin1,tin3); } fa[1]=-1; dfs1(1); ST(); read(m); for(i=1;i<=m;++i) { read(K); con=0; ++timer; t[++con]=1; vis[1]=timer; for(j=1;j<=K;++j) ++con,read(t[con]),vis[t[con]]=timer,isk[t[con]]=timer; work(); } }