C - Many Medians
题意:给n个数(n为偶数),然后问除第i个数以后的(n-1)个数的第(n-1)/2大是多少,输出所有的i.
思路:对原数组copy一份numa[],排序,找出中间的第n/2大和第(n/2)+1大;对于原数组任意一个numb[i],如果numb[i]<=numa[n/2],则剔除numb[i]后,数组numa[]的中间那个值,即第(n-1)/2大的值会向右移一位;如果numb[i]>numa[n/2],则剔除numb[i]后,数组numa[]的中间那个值,即为第(n-1)/2大的值。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
int numa[maxn];
int numb[maxn];
int main() {
int n;
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++) {
scanf("%d",&numa[i]);
numb[i]=numa[i];
}
sort(numa+1,numa+n+1);
int m=n/2;
for(int i=1; i<=n; i++) {
if(numb[i]<=numa[m])
printf("%d\n",numa[m+1]);
else
printf("%d\n",numa[m]);
}
}
return 0;
}
D - Binomial Coefficients
题意:给出n个数,求这n个数中任取两个数a和b,求能使Comb(a,b)最大的a和b;
思路:简单结论题,通过推理可以得知,对于n个数中的最大值num[m],必定存在一个数num[k],使得num[k]最接近num[m]/2这个值,则Comb(num[m],num[k])>=Comb(num[m-1],num[k])>=Comb(num[m-1],num[k-1]),故Comb(num[m],num[k])为最大值,求出num[m]和num[k]即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
int num[maxn];
int cmd(int a,int b) {
return a>b;
}
int main() {
int n;
while(~scanf("%d",&n)) {
for(int i=0; i<n; i++)
scanf("%d",&num[i]);
sort(num,num+n);
int m=num[n-1];
int posa=lower_bound(num,num+n,m/2)-num;
int a=num[posa]; //从右边最逼近m/2的值
sort(num,num+n,cmd);
int posb=lower_bound(num,num+n,m/2,greater<int>())-num;
int b=num[posb]; //从左边最逼近m/2的值
int ans;
if((m-a)>b) //算出哪个逼近的值最优
ans=a;
else
ans=b;
printf("%d %d\n",m,ans);
}
return 0;
}
E - Symmetric Grid
题意:给一个n行m列的矩阵,求是否可以通过行和列的转换变成一个对称矩阵。
思路:swaped[]数组记录配对情况,比如记录swaped[i]=j,swaped[j]=i,意思是第i行和第j行是关于中间n/2行对称的(这是假设的),然后通过dfs枚举出所有的关于行的对称情况(当n为奇数时,有一行关于自己对称,可以理解为这恰好为对称矩阵的第(n+1)/2行)因为对称关系是两两配对的,所以第step==(n+1)/2时,刚好实现所有n行的配对情况,我暂时称为这是一种(n行配对)情况,需要判断它的所有列是否能通过转移达到对称。
这里通过一个check()函数实现,对于一种(n行配对)情况--这种情况是后面列配对的前提,通过对列进行配对,配对的条件是所有的第i列的k行的内容和所有的第j列的swaped[k]行的内容对应相等,如果可以,说明可以通过转移列,使它们在对称的位置。然后计算所有没配对的列,结果为cnt。如果cnt>=2或者列数m为偶数,但cnt==1,即有一列没配对,这些都说明在这种(n行配对)的情况下,无法通过列的转移实现矩阵的对称。如果刚好cnt==1&&列数m为奇数,这说明这一列刚好是这矩阵的中间一列,需要判断这一列是否在(n行配对)的情况下对称。如果也对称了,说明这个矩阵在(n行配对)的情况下相应
转移行,再相应的转换列,便可以实现对称矩阵。
举个栗子,
4 5
rrdca
adrcr
brdgt
tdrgb
(答案:YES)
在swaped[0]=1,swaped[1]=0,swaped[2]=3,swaped[3]=2的n行配对情况下,即第0行和第1行
是对称的,第2行和第3行是对称的。第1列可以和第2列相应配对(转换),说明第2列和第3列可以通过转移到对称的位置上。同理,第1列和第5列相应配对,剩下第3列没配对,进行特判。
#include<bits/stdc++.h>
using namespace std;
const int maxn=20+10;
const int INF=int(1e9)+10;
#define LL long long
char str[maxn][maxn];
int swaped[maxn];
bool used[maxn];
bool ans;
int n,m;
bool check() { //判断在这种(n行配对)的情况下,是否可以通过列的转换实现对称
memset(used,0,sizeof(used));
for(int i=0; i<m; i++) { //枚举任意不相等的两列,在这种(n行配对)的情况下,这两列是否相等
if(used[i]) //相等则说明这两列可以通过列变换形成对称
continue;
for(int j=0; j<m; j++) {
bool vis=true;
if(i==j||used[j])
continue;
for(int k=0; k<n; k++) {
if(str[k][i]==str[swaped[k]][j])
continue;
vis=false;
break;
}
if(vis){
used[i]=used[j]=true;
break;
}
}
}
int cnt=0;
int pos=-1;
for(int i=0; i<m; i++) //计算有多少列没配对
if(!used[i]) {
cnt++;
pos=i;
}
if(cnt>=2||(cnt&&(m%2==0))) //没配对数大于等于2或者(列数为奇数且没配对数等于1)
return false; //的情况都说明这种(n行配对)的情况无法通过列转移实现对称
if(cnt==1) { //对于列数m为奇数的情况,需要特判这一列是否可以形成对称
for(int i=0; i<n; i++) {
if(str[i][pos]!=str[swaped[i]][pos])
return false;
}
}
return true;
}
void dfs(int u,int falg) { //dfs枚举出所有的(n行配对)的情况
if(u==(n+1)>>1) { //u==(n+1)/2,说明所有的行已经配对成功,这是一种(n行配对)的情况
if(check()) //判断列是否通过转换形成对称
ans=true;
return ;
}
if(ans==true)
return;
for(int i=u; i<n; i++) {
if(swaped[i]==-1) {
for(int j=i+1; j<n; j++) {
if(swaped[j]==-1) {
swaped[i]=j;
swaped[j]=i;
dfs(u+1,falg);
swaped[i]=-1;
swaped[j]=-1;
}
}
if(falg) { //对于行数n为奇数的情况,有一行是关于没有对称行的
swaped[i]=i;
dfs(u+1,false);
swaped[i]=-1;
}
}
}
}
void init() {
memset(swaped,-1,sizeof(swaped));
ans=false;
}
int main() {
while(~scanf("%d %d",&n,&m)) {
init();
for(int i=0; i<n; i++)
scanf("%s",str[i]);
if(n&1)
dfs(0,true);
else
dfs(0,false);
printf("%s\n",ans?"YES":"NO");
}
return 0;
}
F - Permutation Tree
看这位大佬的分析得到的灵感点击打开链接
题意:给你一个序列(p1,p2,…,pn) 对于每一个结点(1,2,…,n),两种操作
1.如果pi=1,无需任何操作
2.如果pi≠1,找出最大的j,满足pj<pi,则连接结点i和结点j.
通过序列(p1,p2,…,pn) 可以唯一的构造一棵树。
题目给你n表示有n个结点,然后n-1条边构造一棵树。问是否可以输出一个(p1,p2,…,pn) 序列,通过这个序列构造的树和题目给出的树同构,可以的话,输出满足这个条件的最小字典序的序列。无解的话输出-1。
思路:一开始所有结点先染成黑色,对(p1,p2,…,pn) 序列进行升序排序,考虑的时候仍为原来的i值,定义一个变量tmp=-1,对于排序后的(p1,p2,…,pn) 序列,从左往右扫一遍,对于pi的i>tmp的,对i这个结点染成红色,然后tmp=i;
染色结束后,红色的结点连成的边形成的路径即为这棵树的直径,黑点都一个一个的连接在这些直径上,黑点不会和黑点相连。这样形成的图暂称为“毛虫图”吧。
如果有黑点和黑点直接相连,则肯定写不出(p1,p2,…,pn) 序列的(可以想一下这个样例:
7
1 2
2 3
3 4
4 5
3 6
6 7
(答案:-1)
直径染成红色后,还有两个黑点相连,则没办法写出 (p1,p2,…,pn) 序列。
)
做法是先求出这个树的直径,判断是否能构成“毛虫图”,可以的话,以直径为主,判断以直径的哪一个端点开始为起点,然后重新分配结点的下标,贪心保证字典序最小,具体看代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=400000+10;
int head[maxn]; //前向星的写法,头数组的记录
bool vis[maxn]; //标记数组
int num[maxn]; //记录有多少个子节点
int node[maxn]; //记录结点到子树的结点的最大深度
int que[maxn]; //模拟数组
int nod[maxn]; //记录图的直径上的结点(不包括起点和终点)的连接其他零散点(即不在直径上的点)的个数
struct Edge {
int u,v;
int next;
} edge[maxn];
int n,m; //n个点,m条边
int tol; //前向星的写法,记录边的总数
int cnt; //直径上的点的数量记录
int ans; //答案输出的,因为要最小序列输出,ans不断变化,要记录为全局变量
int S,T; //树的直径的起点和终点
bool flag; //flag记录是否可以构成"毛虫图"
void init() { //初始化
memset(head,-1,sizeof(head));
memset(node,0,sizeof(node));
memset(num,0,sizeof(num));
tol=0;
cnt=0;
ans=1;
flag=true;
}
void add(int u,int v) { //前向星的写法,添加边
edge[tol].u=u;
edge[tol].v=v;
edge[tol].next=head[u];
head[u]=tol++;
}
int bfs(int s) { //bfs求一个点到另一个最远点的距离
int l=0,r=0;
memset(vis,0,sizeof(vis));
memset(que,0,sizeof(que));
que[r++]=s;
vis[s]=1;
while(l<=r) {
s=que[l++];
for(int i=head[s]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(vis[v]==0) {
vis[v]=1;
que[r++]=v;
}
}
}
return que[r-1];
}
void dfs(int u) { //dfs求出结点到子树的结点的最大深度(node[]),判断是否可以构成"毛虫图”
if(!flag) //以及,树的直径上的结点连接其他零散点的个数
return;
int top=0;
vis[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(vis[v]==0) {
dfs(v);
node[u]=max(node[u],node[v]);
if(node[v]>1) top++;
if(v!=T&&node[v]==1)
num[u]++;
}
}
node[u]++;
if(top>=2) { //一个结点,连接有两个及以上的node[]>1的结点 ,肯定无法构成"毛虫图"
flag=false;
return;
}
if(u!=S&&u!=T&&node[u]>=2)
nod[cnt++]=num[u];
}
void printf_(int u) { //用递归的方法输出ans,对于num[u]>0的数,要先输出它的连接点
int t=ans;
vis[u]=1;
if(num[u]>0) {
for(int i=1; i<=num[u]; i++) {
printf("%d ",++ans);
}
}
printf("%d%c",t,u==T?'\n':' ');
ans++;
for(int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(v==T||v==S||node[v]>1) {
if(!vis[v])
printf_(v);
}
}
}
int read() { //数据输入有点大,想试试能快几ms的
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch) {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main() {
while(~scanf("%d",&n)) {
init();
m=n-1;
int u,v;
for(int i=0; i<m; i++) {
//scanf("%d %d",&u,&v);
u=read();
v=read();
add(u,v);
add(v,u);
}
T=bfs(1);
S=bfs(T);
memset(vis,0,sizeof(vis));
dfs(S);
/*cout<<S<<" "<<T<<endl;
cout<<cnt<<endl;
for(int i=1; i<=n; i++)
printf("%d%c",node[i],i==n?'\n':' ');
for(int i=1; i<=n; i++)
printf("%d%c",num[i],i==n?'\n':' ');
for(int i=0; i<cnt; i++)
printf("%d%c",nod[i],i==cnt-1?'\n':' ');
*/
reverse(nod,nod+cnt); //dfs得到的nod[]其实是从T到S的nod[]数据,reverse反转元素的顺序,得到S到T的nod[]数据
for(int i=0; i<cnt; i++) {
if(nod[i]<nod[cnt-i-1]) //nod[i]越大的应该也越往后才输出,这样保证输出的字典序最小
break;
else if(nod[i]>nod[cnt-i-1]) {
swap(S,T);
break;
}
}
memset(vis,0,sizeof(vis));
if(!flag)
printf("-1\n");
else
printf_(S);
}
}
第一次打AtCoder,不小心报了Beginner的,我真的菜爆了╮( ̄▽ ̄"")╭
C - Many Medians
题意:给n个数(n为偶数),然后问除第i个数以后的(n-1)个数的第(n-1)/2大是多少,输出所有的i.
思路:对原数组copy一份numa[],排序,找出中间的第n/2大和第(n/2)+1大;对于原数组任意一个numb[i],如果numb[i]<=numa[n/2],则剔除numb[i]后,数组numa[]的中间那个值,即第(n-1)/2大的值会向右移一位;如果numb[i]>numa[n/2],则剔除numb[i]后,数组numa[]的中间那个值,即为第(n-1)/2大的值。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
int numa[maxn];
int numb[maxn];
int main() {
int n;
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++) {
scanf("%d",&numa[i]);
numb[i]=numa[i];
}
sort(numa+1,numa+n+1);
int m=n/2;
for(int i=1; i<=n; i++) {
if(numb[i]<=numa[m])
printf("%d\n",numa[m+1]);
else
printf("%d\n",numa[m]);
}
}
return 0;
}
D - Binomial Coefficients
题意:给出n个数,求这n个数中任取两个数a和b,求能使Comb(a,b)最大的a和b;
思路:简单结论题,通过推理可以得知,对于n个数中的最大值num[m],必定存在一个数num[k],使得num[k]最接近num[m]/2这个值,则Comb(num[m],num[k])>=Comb(num[m-1],num[k])>=Comb(num[m-1],num[k-1]),故Comb(num[m],num[k])为最大值,求出num[m]和num[k]即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
int num[maxn];
int cmd(int a,int b) {
return a>b;
}
int main() {
int n;
while(~scanf("%d",&n)) {
for(int i=0; i<n; i++)
scanf("%d",&num[i]);
sort(num,num+n);
int m=num[n-1];
int posa=lower_bound(num,num+n,m/2)-num;
int a=num[posa]; //从右边最逼近m/2的值
sort(num,num+n,cmd);
int posb=lower_bound(num,num+n,m/2,greater<int>())-num;
int b=num[posb]; //从左边最逼近m/2的值
int ans;
if((m-a)>b) //算出哪个逼近的值最优
ans=a;
else
ans=b;
printf("%d %d\n",m,ans);
}
return 0;
}
E - Symmetric Grid
题意:给一个n行m列的矩阵,求是否可以通过行和列的转换变成一个对称矩阵。
思路:swaped[]数组记录配对情况,比如记录swaped[i]=j,swaped[j]=i,意思是第i行和第j行是关于中间n/2行对称的(这是假设的),然后通过dfs枚举出所有的关于行的对称情况(当n为奇数时,有一行关于自己对称,可以理解为这恰好为对称矩阵的第(n+1)/2行)因为对称关系是两两配对的,所以第step==(n+1)/2时,刚好实现所有n行的配对情况,我暂时称为这是一种(n行配对)情况,需要判断它的所有列是否能通过转移达到对称。
这里通过一个check()函数实现,对于一种(n行配对)情况--这种情况是后面列配对的前提,通过对列进行配对,配对的条件是所有的第i列的k行的内容和所有的第j列的swaped[k]行的内容对应相等,如果可以,说明可以通过转移列,使它们在对称的位置。然后计算所有没配对的列,结果为cnt。如果cnt>=2或者列数m为偶数,但cnt==1,即有一列没配对,这些都说明在这种(n行配对)的情况下,无法通过列的转移实现矩阵的对称。如果刚好cnt==1&&列数m为奇数,这说明这一列刚好是这矩阵的中间一列,需要判断这一列是否在(n行配对)的情况下对称。如果也对称了,说明这个矩阵在(n行配对)的情况下相应
转移行,再相应的转换列,便可以实现对称矩阵。
举个栗子,
4 5
rrdca
adrcr
brdgt
tdrgb
(答案:YES)
在swaped[0]=1,swaped[1]=0,swaped[2]=3,swaped[3]=2的n行配对情况下,即第0行和第1行
是对称的,第2行和第3行是对称的。第1列可以和第2列相应配对(转换),说明第2列和第3列可以通过转移到对称的位置上。同理,第1列和第5列相应配对,剩下第3列没配对,进行特判。
#include<bits/stdc++.h>
using namespace std;
const int maxn=20+10;
const int INF=int(1e9)+10;
#define LL long long
char str[maxn][maxn];
int swaped[maxn];
bool used[maxn];
bool ans;
int n,m;
bool check() { //判断在这种(n行配对)的情况下,是否可以通过列的转换实现对称
memset(used,0,sizeof(used));
for(int i=0; i<m; i++) { //枚举任意不相等的两列,在这种(n行配对)的情况下,这两列是否相等
if(used[i]) //相等则说明这两列可以通过列变换形成对称
continue;
for(int j=0; j<m; j++) {
bool vis=true;
if(i==j||used[j])
continue;
for(int k=0; k<n; k++) {
if(str[k][i]==str[swaped[k]][j])
continue;
vis=false;
break;
}
if(vis){
used[i]=used[j]=true;
break;
}
}
}
int cnt=0;
int pos=-1;
for(int i=0; i<m; i++) //计算有多少列没配对
if(!used[i]) {
cnt++;
pos=i;
}
if(cnt>=2||(cnt&&(m%2==0))) //没配对数大于等于2或者(列数为奇数且没配对数等于1)
return false; //的情况都说明这种(n行配对)的情况无法通过列转移实现对称
if(cnt==1) { //对于列数m为奇数的情况,需要特判这一列是否可以形成对称
for(int i=0; i<n; i++) {
if(str[i][pos]!=str[swaped[i]][pos])
return false;
}
}
return true;
}
void dfs(int u,int falg) { //dfs枚举出所有的(n行配对)的情况
if(u==(n+1)>>1) { //u==(n+1)/2,说明所有的行已经配对成功,这是一种(n行配对)的情况
if(check()) //判断列是否通过转换形成对称
ans=true;
return ;
}
if(ans==true)
return;
for(int i=u; i<n; i++) {
if(swaped[i]==-1) {
for(int j=i+1; j<n; j++) {
if(swaped[j]==-1) {
swaped[i]=j;
swaped[j]=i;
dfs(u+1,falg);
swaped[i]=-1;
swaped[j]=-1;
}
}
if(falg) { //对于行数n为奇数的情况,有一行是关于没有对称行的
swaped[i]=i;
dfs(u+1,false);
swaped[i]=-1;
}
}
}
}
void init() {
memset(swaped,-1,sizeof(swaped));
ans=false;
}
int main() {
while(~scanf("%d %d",&n,&m)) {
init();
for(int i=0; i<n; i++)
scanf("%s",str[i]);
if(n&1)
dfs(0,true);
else
dfs(0,false);
printf("%s\n",ans?"YES":"NO");
}
return 0;
}
F - Permutation Tree
看这位大佬的分析得到的灵感点击打开链接
题意:给你一个序列(p1,p2,…,pn) 对于每一个结点(1,2,…,n),两种操作
1.如果pi=1,无需任何操作
2.如果pi≠1,找出最大的j,满足pj<pi,则连接结点i和结点j.
通过序列(p1,p2,…,pn) 可以唯一的构造一棵树。
题目给你n表示有n个结点,然后n-1条边构造一棵树。问是否可以输出一个(p1,p2,…,pn) 序列,通过这个序列构造的树和题目给出的树同构,可以的话,输出满足这个条件的最小字典序的序列。无解的话输出-1。
思路:一开始所有结点先染成黑色,对(p1,p2,…,pn) 序列进行升序排序,考虑的时候仍为原来的i值,定义一个变量tmp=-1,对于排序后的(p1,p2,…,pn) 序列,从左往右扫一遍,对于pi的i>tmp的,对i这个结点染成红色,然后tmp=i;
染色结束后,红色的结点连成的边形成的路径即为这棵树的直径,黑点都一个一个的连接在这些直径上,黑点不会和黑点相连。这样形成的图暂称为“毛虫图”吧。
如果有黑点和黑点直接相连,则肯定写不出(p1,p2,…,pn) 序列的(可以想一下这个样例:
7
1 2
2 3
3 4
4 5
3 6
6 7
(答案:-1)
直径染成红色后,还有两个黑点相连,则没办法写出 (p1,p2,…,pn) 序列。
)
做法是先求出这个树的直径,判断是否能构成“毛虫图”,可以的话,以直径为主,判断以直径的哪一个端点开始为起点,然后重新分配结点的下标,贪心保证字典序最小,具体看代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=400000+10;
int head[maxn]; //前向星的写法,头数组的记录
bool vis[maxn]; //标记数组
int num[maxn]; //记录有多少个子节点
int node[maxn]; //记录结点到子树的结点的最大深度
int que[maxn]; //模拟数组
int nod[maxn]; //记录图的直径上的结点(不包括起点和终点)的连接其他零散点(即不在直径上的点)的个数
struct Edge {
int u,v;
int next;
} edge[maxn];
int n,m; //n个点,m条边
int tol; //前向星的写法,记录边的总数
int cnt; //直径上的点的数量记录
int ans; //答案输出的,因为要最小序列输出,ans不断变化,要记录为全局变量
int S,T; //树的直径的起点和终点
bool flag; //flag记录是否可以构成"毛虫图"
void init() { //初始化
memset(head,-1,sizeof(head));
memset(node,0,sizeof(node));
memset(num,0,sizeof(num));
tol=0;
cnt=0;
ans=1;
flag=true;
}
void add(int u,int v) { //前向星的写法,添加边
edge[tol].u=u;
edge[tol].v=v;
edge[tol].next=head[u];
head[u]=tol++;
}
int bfs(int s) { //bfs求一个点到另一个最远点的距离
int l=0,r=0;
memset(vis,0,sizeof(vis));
memset(que,0,sizeof(que));
que[r++]=s;
vis[s]=1;
while(l<=r) {
s=que[l++];
for(int i=head[s]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(vis[v]==0) {
vis[v]=1;
que[r++]=v;
}
}
}
return que[r-1];
}
void dfs(int u) { //dfs求出结点到子树的结点的最大深度(node[]),判断是否可以构成"毛虫图”
if(!flag) //以及,树的直径上的结点连接其他零散点的个数
return;
int top=0;
vis[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(vis[v]==0) {
dfs(v);
node[u]=max(node[u],node[v]);
if(node[v]>1) top++;
if(v!=T&&node[v]==1)
num[u]++;
}
}
node[u]++;
if(top>=2) { //一个结点,连接有两个及以上的node[]>1的结点 ,肯定无法构成"毛虫图"
flag=false;
return;
}
if(u!=S&&u!=T&&node[u]>=2)
nod[cnt++]=num[u];
}
void printf_(int u) { //用递归的方法输出ans,对于num[u]>0的数,要先输出它的连接点
int t=ans;
vis[u]=1;
if(num[u]>0) {
for(int i=1; i<=num[u]; i++) {
printf("%d ",++ans);
}
}
printf("%d%c",t,u==T?'\n':' ');
ans++;
for(int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].v;
if(v==T||v==S||node[v]>1) {
if(!vis[v])
printf_(v);
}
}
}
int read() { //数据输入有点大,想试试能快几ms的
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch) {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main() {
while(~scanf("%d",&n)) {
init();
m=n-1;
int u,v;
for(int i=0; i<m; i++) {
//scanf("%d %d",&u,&v);
u=read();
v=read();
add(u,v);
add(v,u);
}
T=bfs(1);
S=bfs(T);
memset(vis,0,sizeof(vis));
dfs(S);
/*cout<<S<<" "<<T<<endl;
cout<<cnt<<endl;
for(int i=1; i<=n; i++)
printf("%d%c",node[i],i==n?'\n':' ');
for(int i=1; i<=n; i++)
printf("%d%c",num[i],i==n?'\n':' ');
for(int i=0; i<cnt; i++)
printf("%d%c",nod[i],i==cnt-1?'\n':' ');
*/
reverse(nod,nod+cnt); //dfs得到的nod[]其实是从T到S的nod[]数据,reverse反转元素的顺序,得到S到T的nod[]数据
for(int i=0; i<cnt; i++) {
if(nod[i]<nod[cnt-i-1]) //nod[i]越大的应该也越往后才输出,这样保证输出的字典序最小
break;
else if(nod[i]>nod[cnt-i-1]) {
swap(S,T);
break;
}
}
memset(vis,0,sizeof(vis));
if(!flag)
printf("-1\n");
else
printf_(S);
}
}
第一次打AtCoder,不小心报了Beginner的,我真的菜爆了╮( ̄▽ ̄"")╭