HDU 6060 RXD and dividing(LCA)
【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6060
【题目大意】
给一个n个节点的树,要求将2-n号节点分成k部分,
然后将每一部分加上节点1,求每个集合最小斯坦纳树的最大权值和。
【题解】
我们按照后序遍历染色分组,得到的一定是最优分组,
现在考虑在不同颜色的虚树上求路径权值和,
我们发现每个点增加的权值是深度减去到根的路径上已被覆盖的长度,
这个长度等于与dfs序前继的LCA的深度,因此我们在搜索的同时计算与dfs序前继的LCA即可。
But,发现多校题解完全不是我想的这样子。对于每条边来说,他的贡献值是min(k,size),然后dfs一遍即可,实现也很是简单。
Amazing
【代码】
#include <cstdio> #include <algorithm> #include <list> #include <vector> using namespace std; const int N=1000010; typedef long long LL; LL d[N]; int f[N],lst[N],c[N],st[N],en[N],dfn,size[N],son[N]; vector<int> v[N],w[N]; namespace fastIO{ #define BUF_SIZE 100000 bool IOerror=0; inline char nc(){ static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; if(p1==pend){ p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); if(pend==p1){ IOerror=1; return -1; } }return *p1++; } inline bool blank(char ch){ return ch==' '||ch=='\n'||ch=='\r'||ch=='\t'; } inline bool read(int &x){ char ch; while(blank(ch=nc())); if(IOerror)return false; for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0'); return true; } #undef BUF_SIZE }; int n,m,x,y,z; int cnt,D[N],top[N]; LL ans; void dfs(int x){ size[x]=1; for(int i=0;i<v[x].size();i++){ int y=v[x][i]; if(y==f[x])continue; f[y]=x; D[y]=D[x]+1; dfs(y); size[x]+=size[y]; if(size[y]>size[son[x]])son[x]=y; }cnt++; if(cnt>m)cnt=1; c[x]=cnt; } void dfs1(int x,int y){ if(x==-1)return; st[x]=++dfn; top[x]=y; if(son[x])dfs1(son[x],y); for(int i=0;i<v[x].size();i++)if(v[x][i]!=son[x]&&v[x][i]!=f[x])dfs1(v[x][i],v[x][i]); en[x]=dfn; } int lca(int x,int y){ for(;top[x]!=top[y];x=f[top[x]])if(D[top[x]]<D[top[y]]){int z=x;x=y;y=z;} return D[x]<D[y]?x:y; } void dfs2(int x){ int cx=c[x]; if(lst[cx]){ int y=lst[cx]; y=lca(x,y); ans+=d[x]-d[y]; }else ans+=d[x]; lst[cx]=x; for(int i=0;i<v[x].size();i++){ int y=v[x][i],z=w[x][i]; //printf("--%d %d\n",y,z); if(y==f[x])continue; d[y]=d[x]+z; dfs2(y); } } using namespace fastIO; int main(){ while(read(n)){ read(m); ans=0; for(int i=1;i<=n;i++)v[i].clear(),w[i].clear(),lst[i]=0,son[i]=-1; for(int i=1;i<n;i++){ read(x); read(y); read(z); v[x].push_back(y); v[y].push_back(x); w[x].push_back(z); w[y].push_back(z); }dfn=cnt=0; dfs(1); c[1]=0; dfs1(1,1); dfs2(1); printf("%lld\n",ans); }return 0; }
愿你出走半生,归来仍是少年