NC54637. [CSP2019]树上的数(tree)
描述
输入描述
本题输 入包含多组测试数据。
第一行一个正整数 T,表示数据组数。
对于每组测试数据:
第一行一个整数 n,表示树的大小。
第二行 n 个整数,第 i个整数表示数字 i 初始时所在的结点编号。 接下来 n−1 行每行两个整数 x,y,表示一条连接 x 号结点与 y 号结点的边
输出描述
对于每组测试数据,输出一行共 n 个用空格隔开的整数,表示最优操作方案下所 能得到的字典序最小的
示例1
输入:
4 5 2 1 3 5 4 1 3 1 4 2 4 4 5 5 3 4 2 1 5 1 2 2 3 3 4 4 5 5 1 2 5 3 4 1 2 1 3 1 4 1 5 10 1 2 3 4 5 7 8 9 10 6 1 2 1 3 1 4 1 5 5 6 6 7 7 8 8 9 9 10
输出:
1 3 4 2 5 1 3 5 2 4 2 3 1 4 5 2 3 4 5 6 1 7 8 9 10
C++14(g++5.4) 解法, 执行用时: 1756ms, 内存消耗: 49460K, 提交时间: 2019-11-21 12:30:47
#include<bits/stdc++.h> const int N=2005; struct adjacent{ int sz,to[N],o[N],pre[N],nxt[N],s[N],g[N]; inline void add(int x,int zz){to[++sz]=x;o[sz]=zz;} int gfa(int x){return g[x]==x?x:g[x]=gfa(g[x]);} inline void ini(){ memset(pre,-1,sz+2<<2);memset(nxt,-1,sz+2<<2); for(int i=0;i<=sz+1;++i)g[i]=i,s[i]=1<=i && i<=sz; } inline bool ck(int x,int y){ if(nxt[x]==y && pre[y]==x)return 1; if(nxt[x]!=-1 || pre[y]!=-1 || gfa(x)==gfa(y))return 0; if(gfa(x)==gfa(0) && gfa(y)==gfa(sz+1) && s[gfa(x)]+s[gfa(y)]<sz)return 0; return 1; } inline void link(int x,int y){ if(nxt[x]==y)return; nxt[x]=y;pre[y]=x; x=gfa(x);y=gfa(y);g[x]=y;s[y]+=s[x]; } }a[N]; int T,n,x,y,i,p[N],pp[N],mn,faa[N],fee[N]; void dfs(int x,int fa,int fe){ faa[x]=fa;fee[x]=fe; for(int i=1;i<=a[x].sz;++i){ int y=a[x].to[i]; if(y==fa)continue; if(a[x].ck(fe,i)){ if(a[y].ck(a[x].o[i],a[y].sz+1) && y<mn)mn=y; dfs(y,x,a[x].o[i]); } } } int main(){ //// freopen("tree2.in","r",stdin); for(scanf("%d",&T);T--;){ scanf("%d",&n); for(i=1;i<=n;++i)a[i].sz=0; for(i=1;i<=n;++i)scanf("%d",pp+i); for(i=1;i<n;++i)scanf("%d%d",&x,&y),a[x].add(y,a[y].sz+1),a[y].add(x,a[x].sz); for(i=1;i<=n;++i)a[i].ini(); for(i=1;i<=n;++i){ mn=N,dfs(pp[i],0,0),printf("%d%c",mn,i==n?'\n':' '); a[mn].link(fee[mn],a[mn].sz+1); for(x=mn;x!=pp[i];x=faa[x]) a[faa[x]].link(fee[faa[x]],a[x].o[fee[x]]); } } return 0; }
C++(clang++ 11.0.1) 解法, 执行用时: 533ms, 内存消耗: 32212K, 提交时间: 2022-08-03 17:44:34
#include<bits/stdc++.h> using namespace std; #define ll long long int n,p[2005],pre[2005][2005],nxt[2005][2005],con[2005]; vector<int>G[2005]; bool chk(int l,int m,int r) { if(pre[m][r]==-1||nxt[m][l]==-1||nxt[m][l]==r)return 0; if(nxt[m][l]==0&&pre[m][r]==n+1&&con[m]!=2)return 0; return 1; } void uni(int l,int m,int r) { nxt[m][pre[m][r]]=nxt[m][l]; pre[m][nxt[m][l]]=pre[m][r]; pre[m][r]=nxt[m][l]=-1;con[m]--; } int fnd(int x,int p) { int r=n;if(chk(p,x,n+1))r=min(r,x); for(int i=0;i<G[x].size();i++) { int y=G[x][i];if(y==p)continue; if(chk(p,x,y))r=min(r,fnd(y,x)); } return r; } bool del(int x,int t,int p) { if(x==t){uni(p,x,n+1);return 1;} for(int i=0;i<G[x].size();i++) { int y=G[x][i];if(y==p)continue; if(del(y,t,x)){uni(p,x,y);return 1;} } return 0; } void sol() { scanf("%d",&n); for(int i=1;i<=n;i++)G[i].clear(); for(int i=1;i<=n;i++)for(int j=0;j<=n+1;j++)pre[i][j]=nxt[i][j]=j; for(int i=1;i<=n;i++)scanf("%d",&p[i]); for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u); for(int i=1;i<=n;i++)con[i]=G[i].size()+2; for(int i=1;i<=n;i++){int t=fnd(p[i],0);printf("%d ",t);del(p[i],t,0);} puts(""); } int main() { int T;scanf("%d",&T); while(T--)sol();return 0; }