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;
}
时间: 2024-10-24 12:03:51

HDU 6060 RXD and dividing(LCA)的相关文章

HDU 6060 RXD and dividing(dfs 思维)

RXD and dividing Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1893    Accepted Submission(s): 809 Problem Description RXD has a tree T, with the size of n. Each edge has a cost.Define f(S) 

HDU - 2874 Connections between cities (LCA)

After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads h

hdu 6060 RXD and dividing

思路:判断子树节点个数和k的最小值就好了,long long 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e6+10; 5 6 int n,k; 7 vector<pair<int ,ll > > e[N]; 8 ll sum; 9 int a[N]; 10 void dfs(int u,int fa){ 11 a[u]=1; 12 for

hdu 5640 King&#39;s Cake(模拟)

Problem Description It is the king's birthday before the military parade . The ministers prepared a rectangle cake of size n×m(1≤n,m≤10000) . The king plans to cut the cake himself. But he has a strange habit of cutting cakes. Each time, he will cut

hdu 4930 Fighting the Landlords (模拟)

Fighting the Landlords Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 160    Accepted Submission(s): 52 Problem Description Fighting the Landlords is a card game which has been a heat for ye

HDU 4738 Caocao&#39;s Bridges(割边)

乍一看一个模板题,仔细一看还是模板题,但是三个坑.1,不是连通图,放0个.2 守卫为0,放1个. 3注意重边. #include<iostream> #include<cstdio> #include<vector> #include<queue> #include<algorithm> #include<stack> #include<cstring> using namespace std; #define maxn

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

HDU 5624 KK&#39;s Reconstruction(最小生成树)

题目链接:点击打开链接 题意:n个城市, m条可以修建的路, 修每条路有一个费用, 要求修建路将n个城市全部联通,并且最大费用减去最小费用最小. 思路:枚举最小边, 然后重新求一遍最小生成树,复杂度m^2, 出的数据水了, 左边BC水过了.. 细节参见代码: #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #inc

最近公共祖先(lca)

囧啊囧. lca的求法太多了 倍增,tarjan,st,lct,hld.... 后边三个我就不写了,其中st我没写过,估计用不上,在线用倍增,离线用tarjan就行了. 嗯. 第一种,倍增(nlogn,在线): 倍增的思想用在树上,即可以求出lca. 我们维护二维数组,f[i][j],表示i号点的第2^j号祖先,显然2^0=1也就是f[i][0]就是他的父亲 我们需要用dfs维护一个深度数组(求lca需要用) 还需要倍增求出所有的f[i][j],学过st的都应该知道,在这里f[i][j]=f[