[bzoj2286][Sdoi2011]消耗战
来自FallDream的博客,未经允许,请勿转载,谢谢。
一棵n的点的树,有边权;m次询问,每次给定k个点,要求剪断一些边使得点1无法到达这k个点,求最小代价。n<=250000 sigma(ki)<=500000
首先如果只有一个询问的树形dp大家肯定都会吧。
对于一条u->v且边权是w的边,如果v是k个点之一,那么f[u]+=w,否则f[u]+=min(f[v],w)
然后这道题很明显就是要你建出虚树,边权倍增算算呗,然后那么dp就好了啊 复杂度nlogn
然后数据有点坑,写了个假的边权范围,最后一个点会爆int
自己yy的一个虚树建法,感觉好奇怪啊TAT
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define MN 250000 #define MD 17 #define INF 2000000000 #define ll long long using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int fa[MD+1][MN+5],c[MD+5][MN+5],n,m,head[MN+5],cnt=0,dep[MN+5]; int dn=0,dfn[MN+5],a[MN+5],q[MN+5],top,b[MN+5]; ll f[MN+5]; struct edge{int to,next,w;}e[MN*2+5]; bool mark[MN+5]; inline void ins(int f,int t,int w) { e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],w};head[t]=cnt; } void init(int x,int f,int last) { fa[0][x]=f;c[0][x]=last;dfn[x]=++dn; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { dep[e[i].to]=dep[x]+1; init(e[i].to,x,e[i].w); } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j) if(k&1) x=fa[j][x]; if(x==y) return x; for(int i=MD;i>=0;i--) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y]; return fa[0][x]; } int getc(int x,int y) { int mx=INF; for(int i=MD;i>=0;--i) if(dep[fa[i][y]]>=dep[x]) mx=min(mx,c[i][y]),y=fa[i][y]; return mx; } bool cmp(int x,int y){return dfn[x]<dfn[y];} void build() { a[++m]=1;cnt=top=dn=0; sort(a+1,a+m+1,cmp); for(int i=1+(a[1]==a[2]);i<=m;i++) { if(top) { int x=lca(a[i],q[top]); if(x!=q[top]) { while(top>1&&dep[q[top-1]]>=dep[x]) ins(q[top-1],q[top],getc(q[top-1],q[top])),--top; if(top&&q[top]!=x&&dep[q[top-1]]<dep[x]) ins(x,q[top],getc(x,q[top])),q[top]=x; } } q[++top]=a[i]; } for(;top>1;--top) ins(q[top-1],q[top],getc(q[top-1],q[top])); } void dp(int x,int fa) { b[++dn]=x;f[x]=0; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa) { dp(e[i].to,x); if(mark[e[i].to]) f[x]+=e[i].w; else f[x]+=min((ll)e[i].w,f[e[i].to]); } } int main() { n=read(); for(int i=1;i<n;i++) { int u=read(),v=read(),w=read(); ins(u,v,w); } init(dep[1]=1,0,INF); for(int i=0;i<=MD;i++) c[i][0]=INF; for(int j=1;j<=MD;j++) for(int i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]],c[j][i]=min(c[j-1][i],c[j-1][fa[j-1][i]]); memset(head,0,sizeof(head)); for(int T=read();T;--T) { m=read(); for(int i=1;i<=m;i++) mark[a[i]=read()]=1; build();dp(1,0); printf("%lld\n",f[1]); for(int i=1;i<=dn;i++) head[b[i]]=f[b[i]]=mark[b[i]]=0; } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream