HDU5293 : Tree chain problem
问题即:选择价值和最多的链,使得每个点最多被一条链覆盖。
那么考虑其对偶问题:选择最少的点(每个点可以重复选),使得每条链上选了至少$w_i$个点。
那么将链按照LCA的深度从大到小排序,每次若发现点数不够,则在LCA处补充点,树链剖分+线段树维护。
时间复杂度$O(m\log^2n)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=100010,M=262150; int Case,cas,n,m,q,i,op,x,y,z; int g[N],v[N<<1],nxt[N<<1],ed; int size[N],son[N],f[N],d[N],st[N],top[N],dfn; int val[M]; int ans; struct E{int x,y,z,w;}e[N]; inline bool cmp(const E&a,const E&b){return d[a.z]<d[b.z];} inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x){ size[x]=1; for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){ f[v[i]]=x,d[v[i]]=d[x]+1; dfs(v[i]),size[x]+=size[v[i]]; if(size[v[i]]>size[son[x]])son[x]=v[i]; } } void dfs2(int x,int y){ st[x]=++dfn;top[x]=y; if(son[x])dfs2(son[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]); } void build(int x,int a,int b){ val[x]=0; if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } void change(int x,int a,int b,int c,int p){ val[x]+=p; if(a==b)return; int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c,p); else change(x<<1|1,mid+1,b,c,p); } int ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return val[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(x<<1,a,mid,c,d); if(d>mid)t+=ask(x<<1|1,mid+1,b,c,d); return t; } inline int lca(int x,int y){ for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y); return d[x]<d[y]?x:y; } inline int chain(int x,int y){ int t=0; for(;top[x]!=top[y];x=f[top[x]]){ if(d[top[x]]<d[top[y]])swap(x,y); t+=ask(1,1,n,st[top[x]],st[x]); } if(d[x]<d[y])swap(x,y); t+=ask(1,1,n,st[y],st[x]); return t; } inline void gao(int x,int y,int z,int w){ int t=chain(x,y); if(t>=w)return; w-=t; ans+=w; change(1,1,n,st[z],w); } int main(){ scanf("%d",&Case); while(Case--){ scanf("%d%d",&n,&m); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); addedge(x,y),addedge(y,x); } dfs(1); dfs2(1,1); build(1,1,n); for(i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&e[i].w); e[i].x=x,e[i].y=y; e[i].z=lca(x,y); } sort(e+1,e+m+1,cmp); for(i=m;i;i--)gao(e[i].x,e[i].y,e[i].z,e[i].w); printf("%d\n",ans); for(i=0;i<=n;i++)g[i]=size[i]=son[i]=f[i]=d[i]=st[i]=top[i]=0; ed=dfn=ans=0; } }