• CF1205D Almost All 解题报告


    CF1205D Almost All 解题报告:

    更好的阅读体验

    题意

    给定一颗 \(n\) 个点的树,构造树的边权使得对于 \(x\in[1,\lfloor\frac{2n^2}{9}\rfloor]\) 都存在一条路径使得路径边权和为 \(x\)

    \(1\leqslant n\leqslant 1000\)

    分析

    nb 题。

    首先容易构造出一种基本操作:对于一颗 \(n\) 个点的树,根到每个点的路径长度取遍 \(1,2,3,\cdots,n-1\),只需要跑出 dfn 序然后边权等于相邻点 dfn 序之差即可。

    考虑选择一个根,将儿子分成两个部分 A 和 B(大小分别为 \(p,q\)),A 部分使用上面的方法做出 \(1,2,\cdots,p\) 的路径长度,B 部分做出 \(1,2,\cdots,q\) 的路径长度,然后将所有边权乘 \((p+1)\),容易发现这样可以拼凑出 \((p+1)(q+1)-1\) 的所有长度。

    那么我们要选择出一组比较均衡的 \(p,q\) 满足 \((p+1)(q+1)-1\geqslant \lfloor\frac{2n^2}{9}\rfloor\)

    考虑怎么让 \(p,q\) 均衡:

    首先选择重心为根,那么所有子树大小小于等于 \(\lfloor\frac{n}{2}\rfloor\)

    我们只需要将子树按照大小排序,选择一段前缀使得其恰好大于等于 \(\lfloor\frac{n}{3}\rfloor\) 即可,容易发现这些子树的大小之和不超过 \(2\lfloor\frac{n}{3}\rfloor\)

    计算可得上述构造符合条件,于是直接做即可,时间复杂度 \(O(n\log n)\)

    代码

    #include<stdio.h>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn=1005;
    int n,p,ids,dfns;
    int sz[maxn],val[maxn],id[maxn],ok[maxn],fa[maxn],dfn[maxn];
    vector<int>v[maxn];
    void dfs(int x,int last,int f){
    	sz[x]=1;
    	for(int i=0;i<v[x].size();i++)
    		if(v[x][i]!=last)
    			dfs(v[x][i],x,f),sz[x]+=sz[v[x][i]],val[x]=max(val[x],sz[v[x][i]]);
    	val[x]=max(val[x],n-sz[x]);
    	if(f==0&&(p==0||val[p]>val[x]))
    		p=x;
    }
    inline int cmp(int a,int b){
    	return sz[a]<sz[b];
    }
    void get(int x,int last,int val){
    	fa[x]=last,dfn[x]=(++dfns)*val;
    	for(int i=0;i<v[x].size();i++)
    		if(v[x][i]!=last)
    			get(v[x][i],x,val);
    }
    int main(){
    	scanf("%d",&n); 
    	for(int i=1,x,y;i<n;i++)
    		scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
    	dfs(1,0,0),dfs(p,0,1);
    	for(int i=0;i<v[p].size();i++)
    		id[++ids]=v[p][i];
    	sort(id+1,id+1+ids,cmp);
    	int sum=0,k;
    	for(int i=1;i<=ids;i++){
    		ok[id[i]]=1,sum+=sz[id[i]],get(id[i],p,1);
    		if(sum>=n/3){
    			k=i;
    			break;
    		}
    	}
    	dfns=0;
    	for(int i=k+1;i<=ids;i++)
    		get(id[i],p,sum+1);
    	for(int i=1;i<=n;i++)
    		if(i!=p)
    			printf("%d %d %d\n",i,fa[i],dfn[i]-dfn[fa[i]]);
    	return 0;
    }
    
  • 相关阅读:
    UVA 11995
    LA 5031
    防卫导弹
    跳马问题
    UVA 11992
    POJ 3264 Balanced Lineup
    0-1背包
    石子合并
    小技巧
    Android广播中有序和无序的区别
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15679743.html
Copyright © 2020-2023  润新知