版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目链接 gym 101611 2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest Problem C
先讲讲比赛的时候队友想出来的方法(外加我千辛万苦敲出来,错了3发找了3处bug最后封榜后过的)。
很多人都会想到这样的一个问题:如果是一条长链,或者是一个菊花图呢(一个根结点,下面1e5个点)。这是两种不同的类型。
解法一:
那样,我们举例来做这样的一个问题:
我的做法是什么呢?
我把红色的这些直接链缩成一个点,然后把他们放在同一排。
那么,我们可以缩点成为这样
那么,就是我们把链给合成成为一个点了,于是乎,我们只要把所有叶子结点放在目前能放的最底下的一排,然后删除所有的叶子结点(删除?此时拓扑不就是最好的了嘛!),然后,我们是不是会形成新的叶子结点,重复上面的操作,就是可以得到一个从底层上来的知道最后的1号结点一张分层图了,这时候,我们对这张分层图进行bfs遍历,就可以确定它的位置了,对了顺序是要固定的,下面是从后往前,那么往上也得是从后往前,不然会有直线相交的。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxN = 1e5 + 7;
int N, head[maxN], cnt, root[maxN], du[maxN], col[maxN] = {0};
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN<<1];
struct node
{
int x, y, id;
node(int a=0, int b=0, int c=0):x(a), y(b), id(c) {}
}t[maxN];
queue<node> que;
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
queue<int> Q, P;
vector<int> vt[maxN];
void dfs_fa(int u, int fa) //处理父亲节点出来
{
root[u] = fa;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
du[u]++;
dfs_fa(v, u);
}
}
void tp_sort()
{
if(Q.empty()) return;
unordered_set<int> st;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
if(root[u] == 0) continue;
int v = root[u];
if(!v) continue;
du[v]--;
while(!du[v] && !st.count(v) && v)
{
col[v] = col[u];
vt[col[u]].push_back(v);
v = root[v];
if(v != root[u]) du[v]--;
}
if(v == 0) continue;
if(!du[v])
{
P.push(v);
col[v] = v;
vt[v].push_back(v);
}
st.insert(v);
}
while(!Q.empty()) Q.pop();
while(!P.empty()) { Q.push(P.front()); P.pop(); }
tp_sort();
}
int max_y = 1, now_x = 1;
void bfs()
{
while(!que.empty())
{
node now = que.front(); que.pop();
int u = now.id;
if(now.y > max_y) { now_x = 1; max_y = now.y; }
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == root[u]) continue;
if(t[v].x) continue;
t[v] = node(now_x++, now.y+1, v);
que.push(t[v]);
int len = vt[col[v]].size();
for(int j=len-1; j>=0; j--)
{
int id = vt[col[v]][j];
if(t[id].x) continue;
t[id].y = now.y + 1;
t[id].x = now_x++;
t[id].id = id;
if(id ^ v) que.push(t[id]);
}
}
}
}
inline void init()
{
cnt = 0;
for(int i=0; i<=N; i++) head[i] = -1;
while(!Q.empty()) Q.pop();
while(!P.empty()) P.pop();
}
int main() {
scanf("%d", &N);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
_add(u, v);
}
if(N == 1)
{
printf("1 1\n");
return 0;
}
dfs_fa(1, 0);
for(int i=2; i<=N; i++)
{
if(!du[i])
{
Q.push(i);
col[i] = i;
vt[i].push_back(i);
}
}
tp_sort();
if(!col[1])
{
col[1] = 1;
vt[1].push_back(1);
}
int len = vt[col[1]].size();
for(int i=0, u; i<len; i++)
{
u = vt[col[1]][i];
t[u] = node(i + 1, 1, u);
que.push(node(i + 1, 1, u));
}
now_x = 1;
max_y = 1;
bfs();
for(int i=1; i<=N; i++){
printf("%d %d\n", t[i].x, t[i].y);
if(t[i].x > 1000000 || t[i].y > 20)while(1);
}
return 0;
}
/*
13
1 2
1 3
1 4
3 5
3 6
3 7
4 8
6 9
6 10
6 11
7 12
8 13
*/
解法二:
树链剖分!!!
真的好巧妙,要知道重链剖分中的重儿子和轻儿子,重儿子指的是重链上,如果我们把重链放在一个底上,然后不断的向上叠加轻链,我们就能保证其构成一个多叉树的形式,最后能放的结点的个数一定是大于1e5的。
对于上面的树,我们按照重链和轻链的方法,会形成这样的一张图:
第一排是y==1时候,第二排是y==2时候,然后x从上往下递增。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N;
vector<int> E[maxN];
inline void _add(int u, int v)
{
E[u].push_back(v);
E[v].push_back(u);
}
int siz[maxN], Wson[maxN], father[maxN], top[maxN];
struct node
{
int x, y;
node(int a=0, int b=0):x(a), y(b) {}
}t[maxN];
void dfs1(int u, int fa)
{
siz[u] = 1;
father[u] = fa;
int maxx = 0, len = (int)E[u].size();
for(int i=0, v; i<len; i++)
{
v = E[u][i];
if(v == fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > maxx)
{
maxx = siz[v];
Wson[u] = v;
}
}
}
void dfs2(int u, int topy)
{
top[u] = topy;
if(!Wson[u]) return;
t[Wson[u]] = node(t[u].x + siz[u] - siz[Wson[u]], t[u].y);
dfs2(Wson[u], topy);
int det = 0, len = (int)E[u].size();
for(int i=0, v; i<len; i++)
{
v = E[u][i];
if(v == father[u] || v == Wson[u]) continue;
t[v] = node(t[u].x + det, t[u].y + 1);
dfs2(v, v);
det += siz[v];
}
}
inline void init()
{
for(int i=1; i<=N; i++) Wson[i] = 0;
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
_add(u, v);
}
dfs1(1, 0);
t[1] = node(1, 1);
dfs2(1, 1);
for(int i=1; i<=N; i++) printf("%d %d\n", t[i].x, t[i].y);
return 0;
}
/*
13
1 2
1 3
1 4
2 5
2 6
2 7
3 8
6 9
6 10
8 11
11 12
12 13
*/