2018CCPC吉林赛区 hdu6555~hdu6566
2018CCPC吉林赛区(重现赛)- 感谢北华大学
A
基础数论。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int T,cc = 0;
scanf("%d",&T);
while(T --) {
int n;
scanf("%d",&n);
int ans = 0;
for(int i = 1,r;i <= n;i = r + 1) {
r = n / (n / i);
ans += (r-i+1ll) * (n / i) & 1;
}
if(ans&1) printf("Case %d: odd\n",++ cc);
else printf("Case %d: even\n",++ cc);
}
}
B
基础模拟。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int T,cc = 0;
scanf("%d",&T);
map<string,int> mp;
mp["Beijing"] = 8;
mp["Washington"] = -5;
mp["London"] = 0;
mp["Moscow"] = 3;
while(T --) {
int h,m;
string s,name1,name2;
scanf("%d:%d",&h,&m);
cin >> s >> name1 >> name2;
h %= 12;
if(s == "PM") h += 12;
int delta = mp[name2] - mp[name1];
h += delta;
//cout << h << endl;
string rq;
if(h >= 24) rq = "Tomorrow";
else if(h < 0) rq = "Yesterday";
else rq = "Today";
h += 24; h %= 24;
string ans;
if(h <= 11) ans = "AM";
else ans = "PM",h -= 12;
if(h == 0) h = 12;
printf("Case %d: %s %d:%02d %s\n",++ cc,rq.c_str(),h,m,ans.c_str());
}
}
C
基础贪心。也可以写并查集。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int SZ = 2e5 + 10;
int bel[SZ],tot,sum,mark[SZ];
vector<int> g[SZ];
void dfs(int u,int c) {
bel[u] = c;
for(int v : g[u]) {
dfs(v,c);
}
}
int main() {
int T,cc = 0;
scanf("%d",&T);
while(T --) {
int n;
scanf("%d",&n);
for(int i = 1;i <= tot;i ++) {
bel[i] = 0;
mark[i] = 0;
g[i].clear();
}
tot = n,sum = 0;
priority_queue<pii> q;
for(int i = 1;i <= n;i ++) {
int x;
scanf("%d",&x);
q.push(make_pair(x,i));
}
while(q.size()) {
pii p = q.top(); q.pop();
if(p.first <= 1) { mark[p.second] = 1; sum ++; continue; }
if(q.size()) {
pii p2 = q.top(); q.pop();
if(p2.first == p.first) {
pii ans = make_pair(p.first-1,++ tot);
//printf("%d -> %d\n",tot,p.second);
// printf("%d -> %d\n",tot,p2.second);
g[tot].push_back(p.second);
g[tot].push_back(p2.second);
q.push(ans);
}
else q.push(p2);
}
}
if(sum < 2) {
printf("Case %d: NO\n",++ cc);
}
else {
printf("Case %d: YES\n",++ cc);
int t = 0;
for(int i = 1;i <= tot;i ++) {
if(mark[i]) {
dfs(i,t);
if(t==0) t++;
}
}
for(int i = 1;i <= n;i ++) printf("%d",bel[i]); puts("");
}
}
}
D
基础概率DP。由于会加1.5%所以状态要乘2。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int SZ = 2e5 + 10;
double f[333];
int main() {
int T,cc = 0;
scanf("%d",&T);
while(T --) {
int pp;
scanf("%d",&pp);
double p = 1.0*pp/100;
f[200] = 1/p;
for(int i = 199;i >= 4;i --) {
int nx1 = min(200,i+4);
int nx2 = min(200,i+3);
f[i] = p * (i/200.0+(1-i/200.0)*(f[nx1]+1))
+ (1-p) * (f[nx2] + 1);
}
printf("Case %d: %.10f\n",++ cc,f[4]);
}
}
E
推公式数学题。解方程。直接套求根公式比魔改求根公式的精度要高(?)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e3+10;
const int mod=1e9+7;
const double eps=1e-7;
int sgn(double a){
if (fabs(a)<eps) return 0;
if (a>0) return 1;
return -1;
}
int main(){
int T,cas=0; scanf("%d",&T);
while(T--){
double r,h;
scanf("%lf%lf",&r,&h);
double ppx,ppy,ppz,ddx,ddy,ddz;
scanf("%lf%lf%lf",&ppx,&ppy,&ppz);
scanf("%lf%lf%lf",&ddx,&ddy,&ddz);
long double px=ppx,py=ppy,pz=ppz,dx=ddx,dy=ddy,dz=ddz;
long double ox=px,oy=py,oz=pz;
long double k = r*r/h/h;
long double a = dx * dx + dy * dy - k * dz * dz;
long double b = 2 * (dx * ox + dy * oy - k * dz * (oz - h));
long double c = ox * ox + oy * oy - k * (oz - h) * (oz - h);
long double discrim = b * b - 4 * a * c;
long double rootDiscrim = sqrt(discrim);
/*long double q;
if (b < 0) q = (-b + rootDiscrim)/2;
else q = (-b - rootDiscrim)/2;
long double t0 = q / a;
long double t1 = c / q;
long double ans=min(t0,t1);
if(ans < 1e-8) ans = 0;*/
long double ans = (-b-rootDiscrim)/2/a;
printf("Case %d: %.10f\n",++cas,(double)ans);
}
return 0;
}
F
因为左端点递增,所以 i 包含 k 那么 j 一定包含 k,所以 j 取 i-1 最优,每个点的答案就是 x-2。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int SZ = 2e5 + 10;
const int mod = 1e9+7;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
if(flag) n=-n;
return n;
}
int main() {
int T = read(),cc = 0;
while(T --) {
int n = read(),ans = 0;
for(int i = 1;i <= n;i ++) {
int x = read();
x = max(x-2,0);
ans ^= x;
}
printf("Case %d: %d\n",++ cc,ans);
}
}
G
题意:给 \(10^4\) 个一欧姆的电阻。定义一个元件:
- 一个一欧姆电阻是一个元件
- 两个元件并联是一个元件
- 两个元件串联是一个元件
构造一个元件,使得其电阻阻值与 \(r\) 的绝对值之差小于 \(10^{-7}\)
key:随机,乱搞
有连分数做法,不过不太会……
众所周知 n 个 a 欧姆的电阻并联的电阻是 a/n。想要得到一个尽量小的电阻那么一定是若干个一欧姆电阻并联。
考虑把 r 拆分成若干个 1/ki,这其实是埃及分数。我们的目标是使得 \(\sum k_i \le 10^4\) 。
考虑加入一个 1/ki,那么能算出 ki 的下界。每次选下界的贪心是不优的,而我们只需要找到一个较优解。
实际上只需要给下界加一个随机数调整,跑若干遍直到满足条件即可。实测大概跑个几遍就有了,随机了 \(10^5\) 组都能出解。
输出比较坑
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int SZ = 2e5 + 10;
const int mod = 1e9+7;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
if(flag) n=-n;
return n;
}
mt19937 rd(2333);
LL randlr(LL l,LL r) {
return rd()%(r-l+1)+l;
}
vector<int> a;
int work(double r) {
a.clear();
double now = 0;
int sum = 0;
while(fabs(now-r) > 1e-9) {
int k = 1/(r-now); if((r-now)*k<1) k++;
k += randlr(0,5);
now += 1.0/k;
sum += k;
a.push_back(k);
// printf("%.10f %d\n",now,k);
}
// puts("finish");
return sum;
}
int main() {
int T = read(),cc = 0;
while(T --) {
// double r = randlr(1e7,9e7)/1e7;
double r;
scanf("%lf",&r);
printf("Case %d:\n",++ cc);
for(int i = 1;;i ++){
int sum = work(r);
if(sum <= 1e4) {
int m = sum - 1;
printf("%d %d\n",sum,m);
int t = sum-1,lst = 0;
// for(int x : a) cout << x << " "; puts("");
vector<int> b;
for(int x : a) {
printf("1 %d %d\n",lst,lst+1);
lst+=2; t ++; x --;
while(x -- > 1) printf("1 %d %d\n",lst,t),lst++,t++;
b.push_back(t);
}
int x = a.size();
if(x>1) {
printf("0 %d %d\n",b[0],b[1]); t++;
for(int j = 2;j < b.size();j ++)
printf("0 %d %d\n",b[j],t),t++;
}
break;
}
}
}
}
H
基础线段树。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int SZ = 2e5 + 10;
const int mod = 1e9+7;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
if(flag) n=-n;
return n;
}
int mi[SZ];
struct seg {
int l,r;
int sum,misum;
int x,rx,len;
}tree[SZ*4];
void update(int p) {
tree[p].sum = (tree[p<<1].sum+tree[p<<1|1].sum) % mod;
tree[p].misum = (tree[p<<1].misum+tree[p<<1|1].misum) % mod;
}
void build(int p,int l,int r) {
tree[p].l = l;
tree[p].r = r;
tree[p].sum = 0;
tree[p].misum = 0;
tree[p].x = 0;
tree[p].rx = 0;
tree[p].len = 0;
if(l == r) {
tree[p].misum = 1;
return ;
}
int mid = l + r >> 1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
update(p);
}
void pushc(int p,int x,int rx,int len) {
tree[p].sum = (1ll*mi[len]*tree[p].sum%mod+1ll*x*(tree[p].r-tree[p].l+1)%mod
+ 1ll*rx*tree[p].misum%mod*mi[len]%mod) % mod;
tree[p].misum = 1ll*mi[len*2]*tree[p].misum % mod;
tree[p].x = (1ll*tree[p].x*mi[len]%mod + x) % mod;
tree[p].rx = (tree[p].rx + 1ll*rx*mi[tree[p].len] % mod) % mod;
tree[p].len += len;
}
void pushdown(int p) {
if(tree[p].len) {
pushc(p<<1,tree[p].x,tree[p].rx,tree[p].len);
pushc(p<<1|1,tree[p].x,tree[p].rx,tree[p].len);
tree[p].len = 0;
tree[p].x = 0;
tree[p].rx = 0;
}
}
void change(int p,int l,int r,int d) {
if(l<=tree[p].l&&tree[p].r<=r) {
pushc(p,d,d,1);
return ;
}
pushdown(p);
int mid = tree[p].l + tree[p].r >> 1;
if(l <= mid) change(p<<1,l,r,d);
if(mid < r) change(p<<1|1,l,r,d);
update(p);
}
int ask(int p,int l,int r) {
if(l<=tree[p].l&&tree[p].r<=r) {
return tree[p].sum;
}
pushdown(p);
int mid = tree[p].l + tree[p].r >> 1,ans = 0;
if(l <= mid) (ans += ask(p<<1,l,r)) %= mod;
if(mid < r) (ans += ask(p<<1|1,l,r)) %= mod;
return ans;
}
int main() {
mi[0] = 1;
for(int i = 1;i <= 2e5;i ++) mi[i]=mi[i-1]*10ll%mod;
int T = read(),cc = 0;
while(T--) {
int n = read(),m = read();
build(1,1,n);
printf("Case %d:\n",++ cc);
while(m --) {
char s[6];
scanf("%s",s);
int l = read(),r = read();
if(s[0] == 'w') {
int d = read();
change(1,l,r,d);
}
else {
printf("%d\n",ask(1,l,r));
}
}
}
}
I
要么全打完,那么肯定用刚好打过这个怪的打他。要么不打完,那么防御怪都不打,剩下的田忌赛马。
J
题意:给 n 个球, m 个颜色,给出每个球染每个颜色的权值。染完色之后要重排成一个环,使得存在一组重排方案使得任意两个相邻球颜色不同。求权值极差最小值。 \(n,m \le 2000,a_{i,j}\le 10^6\)
key:尺取
题意即为任意颜色不能用超过 n/2 次。
考虑枚举最小值,找到对应的最小的最大值。现在即如何判定是否合法。
如果已知了最小值和最大值,现在要判定。
显然每个球要至少有一个可选颜色。
如果一个球只有一个颜色可选,那么这个球就只能是这个颜色。也就是说对于每个颜色,必选它的球的数目必须小于等于 n/2。现在所有的颜色必选它的球的数目都满足条件,如果对于所有颜色,可选它的球的数目小于等于 n/2,那么一定存在一组方案(显然);否则,即存在一个颜色,可选它的球的数目大于 n/2,以下分类讨论:
- 当 n 是偶数时,因为必选它的球的数目小于等于 n/2,那么我们可以恰好选它 n/2个,用其它颜色补剩下的(因为其他颜色不可能大于n/2)。
- 当 n 是奇数时,此时补全 n/2 后,剩下的球全选另一个颜色会出问题。而这种情况只会出现在仅用两个颜色时(如果用大于等于三种颜色,那么一定有一个可选颜色选第三种,不会出现这种情况)。
仔细观察上述的充要条件,我们我们只需要维护这么几个东西:
- 没有可选颜色的球的个数
- 对于每个颜色,必选它的球的个数
- 有多少个颜色,必选它的个数大于 n/2
- 有多少个颜色可选
对权值排序做双指针,每次是单点插入和删除,上述几个都可以 \(O(1)\) 实现。(对于每个球,加入颜色和删除颜色是按权值递增的;对于每个颜色,每次是必选它的球的个数加一或减一),所以瓶颈就是排个序。你可以用桶排做到 \(O(10^6+nm)\),不过没必要。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<int,LL> pil;
const int SZ = 2e5 + 10;
const int mod = 1e9+7;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
if(flag) n=-n;
return n;
}
int a[SZ],num,lim,colNum,col2[SZ];
void addCol(int x) {
// printf("add color: %d\n",x);
a[x] ++;
if(a[x] == lim) num ++;
}
void delCol(int x) {
// printf("del color: %d\n",x);
if(a[x] == lim) num --;
a[x] --;
}
int noMatchNumber;
queue<int> cols[SZ];
void init(int n,int m) {
for(int i = 1;i <= n;i ++) {
while(cols[i].size()) cols[i].pop();
}
noMatchNumber = n;
for(int i = 1;i <= m;i ++) {
a[i] = 0;
col2[i] = 0;
}
colNum = 0;
num = 0;
lim = n / 2 + 1;
}
void add(pii p) {
int id = p.first,col = p.second;
if(col2[col] == 0) colNum ++;
col2[col] ++;
if(cols[id].size() == 0) {
noMatchNumber --;
addCol(col);
}
else if(cols[id].size() == 1) {
delCol(cols[id].front());
}
cols[id].push(col);
}
void del(pii p) {
int id = p.first,col = p.second;
if(col2[col] == 1) colNum --;
col2[col] --;
assert(!cols[id].empty());
assert(cols[id].front() == col);
if(cols[id].size() == 1) {
noMatchNumber ++;
delCol(cols[id].front());
}
else if(cols[id].size() == 2) {
addCol(cols[id].back());
}
cols[id].pop();
}
int n,m;
bool check() {
if(noMatchNumber) return false;
if(num) return false;
if(n%2==1&&colNum <= 2) return false;
return true;
}
int main() {
int T = read(),cc = 0;
while(T --) {
n = read(),m = read();
init(n,m);
vector<pair<int,pii> > a;
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
a.push_back(make_pair(read(),make_pair(i,j)));
}
}
sort(a.begin(),a.end());
int ans = 1e9;
//for(int i = 0;i < a.size();i ++) printf("%d: %d %d %d\n",i,a[i].first,a[i].second.first,a[i].second.second);
for(int i = 0,j = -1;i < a.size();i ++) {
while(!check() && j+1 < (int)a.size()) add(a[j+1].second),j ++;
if(!check()) break;
// printf("[%d,%d] %d\n",i,j,num);
ans = min(ans,a[j].first - a[i].first);
del(a[i].second);
}
if(ans == 1e9) ans = -1;
printf("Case %d: %d\n",++ cc,ans);
}
}
/**
2
3 3
1 2 100
2 1 200
1 1 300
2 2
1
5 3
2 3 7
2 5 7
2 7 5
2 6 5
7 6 8
4 1
1
1
1
1
*/
K
辣鸡模拟,咕
L
题意:给一个 n 个点的树,每个点有一个重量和价值。可以从树中选出一个独立集,定义 \(f(x)\) 为总重量为 x 的最大价值的方案数,求所有的 \(f(x) (1 \le x \le m)\) 。 \(n \le 50,m \le 5000\)
key:搜索,背包
先放个题解的 \(O(n^2m)\) 的做法:
普通树形背包复杂度 O(nm2),不可取。
考虑在 dfs 序上做 01 背包。对整棵树做轻链剖分, dfs 先走轻儿子,最后再走重儿
子。这样从重儿子子树回溯的时候会直接回到重链顶端
我们所选独立集的后续发展与这条重链的中间节点是否
在独立集内没有关系。从而背包是我们只要记下该节点的 log(n) 个重链顶端是
否在独立集内,该状态的大小为 2^log(n) = n。 dpi,mask,m 表
示走到 i 这个节点, log(n) 个重链顶端的状态为 mask,
所选重量为 m 的最有方案,直接背包。
没太懂那个 log 个重链……所以放个乱搞做法。
考虑折半,瓶颈在于对于两个点集的合并如何 check 是否是独立集。如果能模拟暴力背包的过程,那么只需要记录子树根节点选不选即可,这样合并两个背包是 max 卷积, \(O(m^2)\) 的复杂度。
考虑选重心为根节点,对每个子树暴力搜索独立集得到一个背包,之后按子树根节点选不选来讨论合并。这样能保证搜索最坏情况下是 \(2^{25}\) ,现在来看合并次数。
假设重心的每个子树大小都是 k ,那么搜索独立集的复杂度是 \(O(2^kn/k)\) ,迭代合并的复杂度是 \(O(nm^2/k)\) ,取等号时 k 在 25 左右,如果乘个 T 可能就不太行了。这个最坏情况是链。
子树比较小时可以用一些常数优化,比如只合并背包中合法的元素,合并子树时从小到大之类。
然而数据并没有卡这个乱搞所以就200+ms过了,我估计出题人也没想到
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<int,LL> pil;
const int SZ = 2e5 + 10;
const int mod = 1e9+7;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
if(flag) n=-n;
return n;
}
int n,m;
int A[55],B[55];
int mark[55],xl[55];
vector<int> nodelist,g[55];
void remark(int u,int f) {
nodelist.push_back(u);
for(int v : g[u]) {
if(v == f) continue;
remark(v,u);
}
}
int sz[55];
void predfs(int u,int f) {
sz[u] = 1;
for(int v : g[u]) {
if(v == f) continue;
predfs(v,u);
sz[u] += sz[v];
}
}
int get_centroid(int u) {
predfs(u,0);
int s = sz[u];
while(1) {
int found = 1;
for(int v : g[u]) {
if(sz[v] > sz[u]) continue;
if(sz[v] * 2 >= s) {
u = v; found = 0; break;
}
}
if(found) return u;
}
}
pil up(pil a,pil b) {
pil ans;
ans.first = max(a.first,b.first);
if(a.first == ans.first) ans.second += a.second;
if(b.first == ans.first) ans.second += b.second;
if(!ans.second) ans.first = -1;
return ans;
}
pil a[2][5010];
pil ans[2][5010];
pil tmp[2][5010];
void dfs(int d,int dn,int S,int sa,int sb) {
if(sa>m) return ;
if(d == dn) {
a[S&1][sa] = up(a[S&1][sa],make_pair(sb,1));
return ;
}
int u = nodelist[d];
if(!(xl[u] & S)) dfs(d+1,dn,S^(1<<mark[u]),sa+A[u],sb+B[u]);
dfs(d+1,dn,S,sa,sb);
}
void work(int u,int r) {
nodelist.clear();
remark(u,r);
for(int i = 0;i < nodelist.size();i ++) mark[nodelist[i]] = i;
for(int u : nodelist) {
xl[u] = 0;
for(int v : g[u]) {
if(v == r) continue;
xl[u] ^= 1<<mark[v];
}
}
for(int i = 0;i < 2;i ++)
for(int j = 0;j <= m;j ++) {
tmp[i][j] = make_pair(-1,0);
a[i][j] = make_pair(-1,0);
}
dfs(0,nodelist.size(),0,0,0);
for(int x = 0;x < 2;x ++) {
for(int i = 0;i <= m;i ++) {
if(ans[x][i].second == 0) continue;
for(int y = 0;y < 2;y ++) {
if(x==1&&y==1) continue;
for(int j = 0;i+j <= m;j ++) {
if(a[y][j].second == 0) continue;
int sb = ans[x][i].first+a[y][j].first;
LL t = ans[x][i].second*a[y][j].second;
tmp[x][i+j] = up(tmp[x][i+j],make_pair(sb,t));
}
}
}
}
/*cout << u << endl;
for(int i = 0;i < 2;i ++) {
cout << i << endl;
for(int j = 0;j <= m;j ++) printf("%3d",a[i][j].first); puts("");
for(int j = 0;j <= m;j ++) printf("%3d",a[i][j].second); puts("");
}
for(int i = 0;i < 2;i ++) {
cout << i << endl;
for(int j = 0;j <= m;j ++) printf("%3d",ans[i][j].first); puts("");
for(int j = 0;j <= m;j ++) printf("%3d",ans[i][j].second); puts("");
}
for(int i = 0;i < 2;i ++) {
cout << i << endl;
for(int j = 0;j <= m;j ++) printf("%3d",tmp[i][j].first); puts("");
for(int j = 0;j <= m;j ++) printf("%3d",tmp[i][j].second); puts("");
}
puts("--------");*/
for(int i = 0;i < 2;i ++)
for(int j = 0;j <= m;j ++)
ans[i][j] = tmp[i][j];
}
void bl() {
vector<pil> ans; ans.resize(m+1);
for(int S = 0;S < (1<<n);S ++) {
int sb = 0,sa = 0,b = 0;
for(int i = 0;i < n;i ++) {
if(S>>i&1) {
bool flag = 0;
for(int j : g[i+1]) if(S>>(j-1)&1) flag = 1;
if(flag) { b=1; break;}
sa += A[i+1];
sb += B[i+1];
}
}
if(b) continue;
if(sa>m) continue;
if(ans[sa].first < sb) ans[sa] = make_pair(sb,1);
else if(ans[sa].first == sb) ans[sa].second ++;
}
for(int i = 1;i <= m;i ++) printf("%lld ",ans[i].second); puts("");
}
int main() {
int T = read(),cc = 0;
while(T --) {
n = read(),m = read();
for(int i = 1;i <= n;i ++) A[i]=read(),B[i]=read();
for(int i = 1;i <= n;i ++) g[i].clear();
for(int i = 1;i < n;i ++) {
int x = read(),y = read();
g[x].push_back(y);
g[y].push_back(x);
}
int rt = get_centroid(1);
predfs(rt,0);
sort(g[rt].begin(),g[rt].end(),[](int x,int y) {return sz[x] < sz[y];});
for(int i = 0;i <= m;i ++) {
ans[0][i] = ans[1][i] = make_pair(-1,0);
}
ans[0][0] = make_pair(0,1);
ans[1][A[rt]] = make_pair(B[rt],1);
// cout << rt << endl;
for(int x : g[rt]) work(x,rt);
printf("Case %d:\n",++ cc);
for(int i = 1;i <= m;i ++) {
pil x = up(ans[0][i],ans[1][i]);
printf("%lld%c",x.second,i==m?'\n':' ');
}
//bl();
}
}
/**
1
4 5
1 1
2 2
3 2
2 1
1 2
2 3
3 4
3
3 2
1 1
1 1
1 1
1 2
1 3
4 5
1 1
2 2
3 2
2 1
1 2
2 3
3 4
5 10
3 1
2 2
4 4
7 8
5 16
1 2
1 3
2 4
2 5
*/