2019 ICPC Asia Xuzhou Regional
2019 ICPC Asia Xuzhou Regional
题号 | 标题 | 通过率 | 我的状态 |
---|---|---|---|
A | Cat题库链接 | 240/893 | 通过 |
B | Cats line up 题库链接 | 2/6 | 未通过 |
C | ❤️ numbers 题库链接 | 287/803 | 通过 |
D | Polycut 题库链接 | 0/8 | 未通过 |
E | Multiply 题库链接 | 69/362 | 通过 |
F | The Answer to the Ultimate Question of Life, The Universe, and Everything. 题库链接 | 243/801 | 通过 |
G | Factory 题库链接 | 0/1 | 未通过 |
H | Yuuki and a problem 题库链接 | 22/127 | 通过 |
I | Interesting game 题库链接 | 5/20 | 未通过 |
J | Loli, Yen-Jen, and a graph problem 题库链接 | 20/83 | 未通过 |
K | K-rectangle 题库链接 | 1/5 | 未通过 |
L | Loli, Yen-Jen, and a cool problem 题库链接 | 18/90 | 通过 |
M | M. Kill the tree 题库链接 | 67/584 | 通过 |
A - Cat
每四个组成一组,然后左右端点枚举一下即可(代码写的有点搓)
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int T;
ll l, r, s;
int main() {
cin >> T;
while(T--){
scanf("%lld%lld%lld", &l, &r, &s);
if(r - l + 1 <= 4){
ll res = 0, cur = 0;
for (ll i = l; i<=r;i++){
cur = 0;
for (ll j = i; j <= r;j++){
cur ^= j;
if(cur <= s)
res = max(res, j - i + 1);
}
}
printf("%lld\n", res ? res : -1);
continue;
}
ll res = 0;
if(l % 2 == 0){
ll nr = (r - l + 1) / 4 * 4 + l;
ll cur = 0;
for (ll j = nr; j <= r; j++) {
cur ^= j;
if(cur <= s)
res = max(res, j - nr + 1);
}
res += nr - l;
}
if(l % 2 == 1){
ll nl = l + 1;
ll nr = (r - nl + 1) / 4 * 4 + nl;
ll cur = 0;
for (ll j = nr; j <= r;j++){
cur ^= j;
if(cur <= s)
res = max(res, j - nr + 1);
}
cur = l;
if(cur <= s)
res = max(res, 1ll);
for (ll j = nr; j <= r;j++){
cur ^= j;
if(cur <= s)
res = max(res, j - nr + 2);
}
res += nr - nl;
}
printf("%lld\n", res);
}
return 0;
}
C - ❤️ numbers
当区间长度特别长时,素数个数是非常少的,参考:https://baike.baidu.com/item/%E7%B4%A0%E6%95%B0%E5%88%86%E5%B8%83/369166
所以大区间直接输出Yes,小区间暴力判断即可。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 100000 + 5;
int T, l, r;
bool prime(int x){
if(x == 1 || x == 2)
return true;
for (int i = 2; i <= x / i;i++){
if(x % i == 0)
return false;
}
return true;
}
bool check(int l,int r){
int num = 0;
for (int i = l; i <= r;i++){
if(prime(i))
num++;
}
if(3 * num < r - l + 1)
return true;
else
return false;
}
int main() {
scanf("%d", &T);
while(T--){
scanf("%d%d", &l, &r);
if(r - l + 1 >= 50){
puts("Yes");
}else{
puts(check(l, r) ? "Yes" : "No");
}
}
return 0;
}
E - Multiply
令\(Z = a_1!\times a_2! \times \cdots \times a_n!\)
找最大的 \(i\) 使得 \(Z\times X^i\) 是 \(Y!\) 的因子,首先求出 \(X!\) 的所有质因数和其指数,然后遍历这些质因数,对于所有\(a_i!\),以及\(Y!\),求出其对\(X\) 的指数的贡献,取所有质因数里面最小的那个即可。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
/*
Miller_Rabin 算法进行素数测试
速度快可以判断一个 < 2^63 的数是不是素数
*/
const int S = 8;
typedef long long ll;
//计算 res = (a*b)%c
ll mult_mod(ll a, ll b, ll c){
a %= c;
b %= c;
ll res = 0;
ll tmp = a;
for (; b;b>>=1){
if(b & 1) {
res += tmp;
if(res > c)
res -= c;
}
tmp <<= 1;
if(tmp > c)
tmp -= c;
}
return res;
}
ll pow_mod(ll a,ll b, ll mod){
ll res = 1;
a %= mod;
for (; b;b>>=1){
if(b & 1)
res = mult_mod(res, a, mod);
a = mult_mod(a, a, mod);
}
return res;
}
/*
通过 a^(n-1)=1(mod n)来判断 n 是不是素数
n - 1 = x * 2^t 中间使用二次判断
是合数返回true,不一定是合数返回false
*/
bool check(ll a,ll n,ll x,ll t){
ll res = pow_mod(a, x, n);
ll last = res;
for (int i = 1; i <= t;i++){
res = mult_mod(res, res, n);
if(res == 1 && last != 1 && last != n-1)
return true;
last = res;
}
if(res != 1)
return true;
return false;
}
/*
Miller_Rabin 算法
是素数返回true
不是素数返回false
*/
bool Miller_Rabin(ll n){
if(n < 2)
return false;
if(n == 2)
return true;
if((n&1) == 0)
return false;
ll x = n - 1;
ll t = 0;
while((x & 1) == 0) {
x >>= 1, t++;
}
for (int i = 0; i < S;i++){
ll a = rand() % (n - 1) + 1;
if(check(a,n,x,t))
return false;
}
return true;
}
/*
Pollard_rho 算法进行质因数分解
*/
ll fac[100];
int tol;
ll gcd(ll a,ll b){
ll t;
while(b){
t = a;
a = b;
b = t % b;
}
if(a >= 0)
return a;
else
return -a;
}
//找出一个因子
ll pollard_rho(ll x,ll c){
ll i = 1, k = 2;
ll x0 = rand() % (x - 1) + 1;
ll y = x0;
while(1){
i++;
x0 = (mult_mod(x0, x0, x) + c) % x;
ll d = gcd(y - x0, x);
if(d != 1 && d != x)
return d;
if(y == x0)
return x;
if(i == k) {
y = x0;
k += k;
}
}
}
//对 n 进行质因数分解,存入factor,k设置为107左右
void findfac(ll n,int k){
if(n == 1)
return;
if(Miller_Rabin(n)){
fac[tol++] = n;
return;
}
ll p = n;
int c = k;
while(p >= n)
p = pollard_rho(p, c--);
findfac(p, k);
findfac(n / p, k);
}
//POJ 1811
// 给出一个N,如果是素数输出Prime,否则输出最小的素因子
ll a[100010];
int main(){
int T;
ll n,x,y;
scanf("%d", &T);
while(T--){
tol = 0;
scanf("%lld%lld%lld", &n, &x, &y);
for (int i = 1; i <= n;i++){
scanf("%lld", &a[i]);
}
ll res = 1ll << 60;
findfac(x, 127);
for (int i = 0; i < tol;i++){
ll now = 0;
while(x % fac[i] == 0){
now++;
x /= fac[i];
}
if(now == 0) continue;
ll nu = 0, tp, w;
//cout << fac[i] << endl;
for (int j = 1; j <= n;j++){
tp = log(a[j]) / log(fac[i]);
w = 1;
for (int k = 1; k <= tp;k++)
w *= fac[i], nu -= a[j] / w;
}
w = 1;
tp = log(y) / log(fac[i]);
for (int k = 1; k <= tp;k++)
w *= fac[i], nu += y / w;
res = min(res, nu/now);
}
printf("%lld\n", res);
}
}
F - The Answer to the Ultimate Question of Life, The Universe, and Everything.
\(a^3+b^3+c^3=x\) 已知 \(y=x^3\) 在实数域上严格单调递增,所以枚举一个a,然后枚举一个b,根据确定的x求出c,然后再根据c的值对b进行调整(双指针),可以预处理出来合法的\(a^3+b^3+c^3=x\) ,复杂度是\(O(n*5000^2)\) ,打表出来直接输出即可。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 5000 + 5;
struct node{
int a, b, c;
} a[201];
bool b[201];
void init(){
a[0] = {5000,0,-5000};
a[1] = {5000,1,-5000};
a[2] = {4375,-486,-4373};
a[3] = {4,4,-5};
b[4] = 1;
b[5] = 1;
a[6] = {644,-205,-637};
a[7] = {168,44,-169};
a[8] = {5000,2,-5000};
a[9] = {217,-52,-216};
a[10] = {683,-353,-650};
a[11] = {843,-641,-695};
a[12] = {10,7,-11};
b[13] = 1;
b[14] = 1;
a[15] = {332,-262,-265};
a[16] = {4118,-588,-4114};
a[17] = {2977,2195,-3331};
a[18] = {1671,-1276,-1373};
a[19] = {91,47,-95};
a[20] = {2833,-741,-2816};
a[21] = {445,-287,-401};
b[22] = 1;
b[23] = 1;
a[24] = {8,8,-10};
a[25] = {2357,1839,-2683};
a[26] = {2106,237,-2107};
a[27] = {5000,3,-5000};
a[28] = {2269,-249,-2268};
a[29] = {235,-69,-233};
b[30] = 1;
b[31] = 1;
b[32] = 1;
b[33] = 1;
a[34] = {1557,-244,-1555};
a[35] = {1154,-509,-1120};
a[36] = {2731,2358,-3223};
a[37] = {445,-84,-444};
a[38] = {25,16,-27};
b[39] = 1;
b[40] = 1;
b[41] = 1;
b[42] = 1;
a[43] = {837,-307,-823};
a[44] = {8,-5,-7};
a[45] = {2025,1709,-2369};
a[46] = {815,-473,-758};
a[47] = {139,49,-141};
a[48] = {3991,-1247,-3950};
b[49] = 1;
b[50] = 1;
a[51] = {659,602,-796};
b[52] = 1;
a[53] = {2141,1518,-2370};
a[54] = {3891,-648,-3885};
a[55] = {3131,1837,-3329};
a[56] = {559,505,-672};
a[57] = {982,361,-998};
b[58] = 1;
b[59] = 1;
a[60] = {1202,-163,-1201};
a[61] = {845,668,-966};
a[62] = {2903,-1561,-2744};
a[63] = {146,102,-161};
a[64] = {5000,4,-5000};
a[65] = {903,403,-929};
a[66] = {4,1,1};
b[67] = 1;
b[68] = 1;
a[69] = {398,134,-403};
a[70] = {2325,824,-2359};
a[71] = {443,401,-533};
a[72] = {434,-104,-432};
a[73] = {344,-146,-335};
b[74] = 1;
b[75] = 1;
b[76] = 1;
b[77] = 1;
a[78] = {2123,-829,-2080};
a[79] = {711,-196,-706};
a[80] = {1366,-706,-1300};
a[81] = {2638,-1719,-2368};
a[82] = {1188,847,-1317};
a[83] = {3651,1315,-3707};
b[84] = 1;
b[85] = 1;
b[86] = 1;
a[87] = {4271,-1972,-4126};
a[88] = {1686,-1282,-1390};
a[89] = {2036,1953,-2514};
a[90] = {1798,365,-1803};
a[91] = {3992,-2912,-3389};
a[92] = {4039,861,-4052};
a[93] = {253,-98,-248};
b[94] = 1;
b[95] = 1;
a[96] = {20,14,-22};
a[97] = {3200,-991,-3168};
a[98] = {2391,-1638,-2101};
a[99] = {984,-622,-893};
a[100] = {1870,-903,-1797};
a[101] = {2325,319,-2327};
a[102] = {229,118,-239};
b[103] = 1;
b[104] = 1;
a[105] = {8,-4,-7};
a[106] = {2760,-1165,-2689};
a[107] = {1117,947,-1309};
a[108] = {1345,-948,-1165};
a[109] = {2924,853,-2948};
b[110] = 1;
a[111] = {4966,-2312,-4793};
b[112] = 1;
b[113] = 1;
b[114] = 1;
a[115] = {11,8,-12};
a[116] = {1945,-757,-1906};
a[117] = {962,-555,-896};
a[118] = {4327,383,-4328};
a[119] = {3789,-1673,-3677};
a[120] = {2725,1219,-2804};
b[121] = 1;
b[122] = 1;
a[123] = {38,-16,-37};
a[124] = {5,0,-1};
a[125] = {5000,5,-5000};
a[126] = {2217,-419,-2212};
a[127] = {4988,-3881,-4034};
a[128] = {3997,-726,-3989};
a[129] = {1801,-1238,-1580};
b[130] = 1;
b[131] = 1;
a[132] = {5,2,-1};
a[133] = {389,167,-399};
a[134] = {3203,-1766,-3013};
a[135] = {1395,-629,-1351};
a[136] = {946,816,-1116};
a[137] = {801,-428,-758};
a[138] = {103,-77,-86};
b[139] = 1;
b[140] = 1;
a[141] = {116,104,-139};
a[142] = {8,-3,-7};
b[143] = 1;
a[144] = {3342,-2552,-2746};
a[145] = {10,-7,-8};
a[146] = {376,-263,-327};
a[147] = {2131,1528,-2366};
b[148] = 1;
b[149] = 1;
a[150] = {317,260,-367};
a[151] = {447,215,-463};
a[152] = {741,486,-805};
a[153] = {3744,-695,-3736};
a[154] = {2145,-516,-2135};
a[155] = {3721,-1049,-3693};
b[156] = 1;
b[157] = 1;
b[158] = 1;
a[159] = {1526,383,-1534};
a[160] = {3972,-1654,-3874};
a[161] = {4980,-2476,-4767};
a[162] = {4180,-1417,-4125};
a[163] = {4033,-2943,-3423};
a[164] = {79,-59,-66};
b[165] = 1;
b[166] = 1;
b[167] = 1;
a[168] = {890,-574,-802};
a[169] = {1521,-1012,-1354};
a[170] = {4047,-2149,-3834};
a[171] = {1178,891,-1328};
b[172] = 1;
b[173] = 1;
a[174] = {349,-170,-335};
b[175] = 1;
b[176] = 1;
a[177] = {1169,-160,-1168};
a[178] = {15,-10,-13};
a[179] = {2691,1503,-2839};
b[180] = 1;
a[181] = {4861,974,-4874};
a[182] = {91,-29,-90};
a[183] = {4876,976,-4889};
b[184] = 1;
b[185] = 1;
a[186] = {5,5,-4};
a[187] = {2000,-1092,-1885};
a[188] = {1635,318,-1639};
a[189] = {1974,-1403,-1702};
a[190] = {4815,-593,-4812};
a[191] = {399,-215,-377};
a[192] = {16,16,-20};
b[193] = 1;
b[194] = 1;
b[195] = 1;
a[196] = {1112,-579,-1057};
a[197] = {3026,-1606,-2867};
a[198] = {3809,-1347,-3752};
a[199] = {2199,508,-2208};
a[200] = {2334,-638,-2318};
}
int main() {
int T, x;
cin >> T;
init();
while(T--){
cin >> x;
if(b[x])
printf("impossible\n");
else
printf("%d %d %d\n", a[x].a, a[x].b, a[x].c);
}
return 0;
}
H - Yuuki and a problem
问题关键如何快速求一个集合中可以组成的数字集的mex。
首先考虑区间中数字范围在[1,1] 中的和 sum,
若 sum = 0, 则 答案为1, 否则可以组成[1,sum]
中的任意一个数字。
然后考虑区间中数字在[1, sum+1] 中的和 nsum,这表示可以组成[1.nsum]
中的任意一个数字,因为[1,1]就可以组成了[1,sum]
,如果再多一个数字 x
,那么就可以组成[x,x+sum]
,我们只有在[2, sum+1]中找到这样的x
,也就是说nsum != sum
, 才能使得 sum+1
可以被组成,否则 sum+1
就是第一个无法组成的数字。
然后我们令sum = nsum,继续查询[1, sum+1]
中数字的和即可。
sum的增长速度应该是超过了斐波那契,所以查询次数很少。待修改的查询区间内[l,r]中的数字和,可以用树状数组维护权值线段树
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 200000 + 5;
int n, m, q, a[N], L[30][30], R[30][30], cl, cr;
inline int lowbit(int x) { return x & -x; }
struct Seg{
struct node{
int ls, rs;
ll sum;
void init() { ls = rs = sum = 0; }
} t[N * 100];
int rt[N], tot;
ll res;
int newnode(){
++tot;
t[tot].init();
return tot;
}
void init() { memset(rt, 0, sizeof rt); tot = 0;}
void update(int &rt, int l,int r,int pos,int v){
if(!rt)
rt = newnode();
t[rt].sum += v;
if(l == r)
return;
int mid = l + r >> 1;
if(pos <= mid)
update(t[rt].ls, l, mid, pos, v);
else
update(t[rt].rs, mid + 1, r, pos, v);
}
void update(int x, int pos, int v) {
for (; x <= n; x += lowbit(x)) {
update(rt[x], 1, m, pos, v);
}
}
void query(int dep, int l,int r,int ql,int qr){
if(ql > qr)
return;
if(l >= ql && r <= qr){
for (int i = 1; i <= cl;i++)
res -= t[L[dep][i]].sum;
for (int j = 1; j <= cr;j++)
res += t[R[dep][j]].sum;
return;
}
int mid = l + r >> 1;
if(ql <= mid){
for (int i = 1; i <= cl;i++)
L[dep + 1][i] = t[L[dep][i]].ls;
for (int i = 1; i <= cr;i++)
R[dep + 1][i] = t[R[dep][i]].ls;
query(dep + 1, l, mid, ql, qr);
}
if(qr > mid){
for (int i = 1; i <= cl;i++)
L[dep + 1][i] = t[L[dep][i]].rs;
for (int i = 1; i <= cr;i++)
R[dep + 1][i] = t[R[dep][i]].rs;
query(dep + 1, mid + 1, r, ql, qr);
}
}
} seg;
int main() {
m = 2e5;
while(~scanf("%d%d",&n,&q)){
for (int i = 1; i <= n;i++)
scanf("%d", &a[i]);
seg.init();
for (int i = 1; i <= n;i++){
seg.update(i, a[i], a[i]);
}
int op, x, y;
while(q--){
scanf("%d%d%d", &op, &x, &y);
if(op == 1){
seg.update(x, a[x], -a[x]);
a[x] = y;
seg.update(x, a[x], a[x]);
} else {
--x;
cl = cr = 0;
for (int i = x; i; i -= lowbit(i)){
L[0][++cl] = seg.rt[i];
}
for (int i = y; i; i-= lowbit(i)){
R[0][++cr] = seg.rt[i];
}
ll l = 0, r = 0;
do{
r = l + 1;
seg.res = 0;
seg.query(0, 1, m, 1, min(1ll * m, r));
l = seg.res;
} while (l >= r);
printf("%lld\n", l + 1);
}
}
}
return 0;
}
L - Loli, Yen-Jen, and a cool problem
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 300000 + 5;
const int P = 26;
int n, q;
char s[N];
int root, tr[N][P], cnt[N], tot, trie_id[N], sam_pos[N];
int add(int u, char ch){
int c = ch - 'A';
if(!tr[u][c]) tr[u][c] = ++tot;
u = tr[u][c];
cnt[u] ++;
return u;
}
struct node{
int link, len, trans[P], endpos;
};
struct SAM{
node S[2*N];
int head[2*N], ver[2*N], nxt[2*N];
int size,tot, fa[2*N][20];
void add(int x, int y){ver[++tot] = y; nxt[tot] = head[x],head[x] = tot;}
SAM():size(1){}
int insert(int p, char ch, int cnt){
int x = ch - 'A';
int np = ++size;
S[np].len = S[p].len + 1;
S[np].endpos = cnt;
while(p != 0 && !S[p].trans[x]) S[p].trans[x] = np, p = S[p].link;
if(p == 0)S[np].link = 1;
else{
int q, nq;
q = S[p].trans[x];
if(S[q].len == S[p].len + 1) S[np].link = q;
else{
nq = ++size;
S[nq] = S[q];
S[nq].len = S[p].len + 1;
S[nq].endpos = 0;
S[np].link = S[q].link = nq;
while(p != 0 && S[p].trans[x] == q) S[p].trans[x] = nq, p = S[p].link;
}
}
return np;
}
void dfs(int x, int f){
fa[x][0] = f;
for(int i=head[x];i;i=nxt[i]){
int y = ver[i];
dfs(y, x);
S[x].endpos += S[y].endpos;
}
}
void build(){
for(int i=2;i<=size;i++){
if(S[i].link) add(S[i].link, i);
}
dfs(1,0);
for(int j=1;j<20;j++){
for(int i=1;i<=size;i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
}
}
int query(int u, int len){
for(int i=19;i>=0;i--)if(S[fa[u][i]].len >= len) u = fa[u][i];
return S[u].endpos;
}
}sam;
void bfs(int u){
queue<int> q;
q.push(u);
sam_pos[u] = 1;
while(q.size()){
int x = q.front();q.pop();
for(int i=0;i<P;i++){
int y = tr[x][i];
if(!y)continue;
q.push(y);
sam_pos[y] = sam.insert(sam_pos[x], 'A'+i, cnt[y]);
}
}
}
int main() {
scanf("%d%d",&n,&q);
scanf("%s",s+1);
root = tot = 1;
trie_id[1] = add(root, s[1]);
for(int i=2;i<=n;i++){
int fa;scanf("%d",&fa);
trie_id[i] = add(trie_id[fa], s[i]);
}
bfs(root);
sam.build();
while(q--){
int x, len;scanf("%d%d",&x, &len);
printf("%d\n", sam.query(sam_pos[trie_id[x]], len));
}
return 0;
}
/*
6 3
ABABBA
1 1 3 3 4
2 2
2 1
6 4
*/
M - Kill the tree
对于以 x 为根的某棵子树,其重心只可能是 x,或者在 x 的重儿子上,所以只需要将 以x 的重儿子 y 为根的子树的重心向上提就好。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 200000 + 5;
int head[N], ver[N << 1], nxt[N << 1], tot;
int n, f[N], son[N];
ll d[N],sz[N];
vector<int> res[N];
void add(int x,int y){
ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
void dfs(int x,int fa){
sz[x] = 1;
for (int i = head[x]; i;i=nxt[i]){
int y = ver[i];
if(y == fa)
continue;
f[y] = x;
dfs(y, x);
sz[x] += sz[y];
d[x] += d[y] + sz[y];
if(sz[y] >= sz[son[x]])
son[x] = y;
}
if(sz[x] == 1 || sz[son[x]] * 2 < sz[x]){//sz[son[x]]*2<sz[x]表示重心是x,因为重心如果从x向下移只会使得更加不平衡
res[x].push_back(x);
return;
}
for (int j = 0; j < res[son[x]].size();j++){
int v = res[son[x]][j];
while (v != x && sz[v] < sz[x] - sz[v])//不断向上提
v = f[v];
res[x].push_back(v);
if (v != x && sz[v] == sz[x] - sz[v])//此时发现有存在两个重心的情况
res[x].push_back(f[v]);
}
sort(res[x].begin(), res[x].end());
res[x].erase(unique(res[x].begin(), res[x].end()), res[x].end());
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n;i++){
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
for (int i = 1; i <= n;i++){
if(res[i].size() == 1)
printf("%d\n", res[i][0]);
else
printf("%d %d\n", res[i][0], res[i][1]);
}
return 0;
}