- Gym - 101611C Carpet
- 题目大意
- 分析
给你一个n(1<=n<=1e5),表示树的结点个数为n,接下来n-1行输入ui和vi,表示结点u和结点v之间有一条边,现在需要你把这棵树放在一个x*y的矩形中(1<=x<=1e6,1<=y<=20),且没有边交叉。然后输出树上的每个结点在矩形中的坐标。分析
显然对于结点个数来说,x是一个极度富裕的值,而y是个珍稀值。 那么我们很容易就想到将这个树根据树的深度,选择纵向延展或者是横向延展。 以深度20为分界线。
#includeusing namespace std; const int maxn = 1e6+10; typedef long long ll; struct node{ int next, to; }mp[maxn]; int head[maxn],cnt=0; int dep[maxn],vis[maxn]={0}; int Y[maxn],X[maxn];//X和Y中存着对应下标的深度能放结点的位置 int y[maxn],x[maxn];//x和y中存的是下标对应的位置 int max_dep=0; void add(int u,int v){ mp[++cnt].next = head[u]; mp[cnt].to = v; head[u] = cnt; } //第一次深搜跑出最大的深度和各结点的深度 void dfs(int n){ vis[n]=1; max_dep=max(max_dep,dep[n]); for(int i=head[n];i;i=mp[i].next){ int To = mp[i].to; if(!vis[To]){ dep[To] = dep[n] + 1; dfs(To); } } } //纵向延展时x的值 void dfsx(int n){ vis[n] = 1; x[n] = X[dep[n]]; X[dep[n]]++; for(int i = head[n]; i; i = mp[i].next){ int To = mp[i].to; if(!vis[To]){ dfsx(To); } } } //横向延展时y的值 void dfsy(int n){ vis[n] = 1; y[n] = Y[dep[n]]; Y[dep[n]]++; for(int i = head[n]; i; i = mp[i].next){ int To = mp[i].to; if(!vis[To]){ dfsy(To); } } return ; } int main(){ int n; scanf("%d",&n); for(int i=1;i 这个思路是很容易想到的,但是对于1<=n<=1e5来说,可以很轻易的构造出一深度大于20,且同一深度大于20个结点的树。
所以理所当然的wa3了
这时候就想到了树剖。
我们知道重链剖分可以将树分为重子树和轻子树,而轻子树的结点个数一定小于n/2.
我们可以把1看做根放到(1,1),然后上面提到过x的值是十分富裕的,我们就可以保证每个结点的x都是独立的,然后根据下面的规则来放置:
- 先放置轻子节点,后放置重子节点。
- 轻子节点放置于父节点的上一层,重子节点放置于父节点的同一层。
然后来证明这个方法不会超过y的上限。
我们知道剖分之后可以分为重子节点所在的子树-重子树,和轻子节点所在的子树-轻子树。同时轻子树的结点个数一定是比n/2要小的。那么根据上述方法去放置的时候,只有当遇到轻子节点的时候才会向上放,那么如果向上放置超过最大的y,就需要满足n> 2^20>1e6,而n最大为1e5,所以它是不会超了y的上限的。
AC代码#includeusing namespace std; const int maxn = 1e6+100; typedef long long ll; int siz[maxn],hson[maxn]; int head[maxn],cnt=0; void init(){ memset(head,0,sizeof(head)); } struct node{ int to,next; }mp[maxn]; void add(int u,int v){ mp[++cnt].next=head[u]; mp[cnt].to=v; head[u]=cnt; } //对于这道题来说剖分只需要把子树大小和重子节点跑出来即可 void dfs1(int f,int u){ hson[u] = -1; siz[u] = 1; for(int i=head[u];i;i=mp[i].next) { int To=mp[i].to; if(To == f) continue; dfs1(u,To); siz[u]+=siz[To]; if(hson[u]==-1||siz[To]>siz[hson[u]]) hson[u]=To; } } int x[maxn],y[maxn]; int tot = 0; void dfs2(int f,int u,int t){ x[u] = ++tot; y[u] = t; if(hson[u]==-1) return; for(int i = head[u]; i;i = mp[i].next){ int To = mp[i].to; if(To == f || To == hson[u]) continue; dfs2(u,To,t+1); } dfs2(u,hson[u],t); } int main(){ int n; scanf("%d",&n); init(); for(int i = 1; i < n; i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs1(0,1); dfs2(0,1,1); for(int i = 1; i <= n; i++) printf("%d %dn",x[i],y[i]); return 0; }



