纯模拟题,不需要使用任何算法。(如果一定要说一个算法思想,递归)
难点在于区分两种情况:直接锁定答案和排除法只剩答案 。前者最后输出,后者不输出。
观察可知,每个节点最多只被搜索一次,所以如果答案节点第一次被搜索时未能结束搜索,最后一定会进入排除法情况。
小心数据结构,不要爆时空。
代码如下:(15ms 3MB过)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2001,M=101,MAX=0x7fffffffffffffff;
ll n,m,t;
ll p[N],s[N],w[N],re[N];
vector<ll>A[N],a[N];
ll su(ll be)
{
if(a[be].size()==0)
{
s[be]=w[be];
return s[be];
}
ll sum=w[be];
for(int i=0; i<a[be].size(); i++)
{
sum+=su(a[be][i]);
}
s[be]=sum;
return s[be];
}
bool ifchild(ll root,ll an)
{
if(root==an)return 1;
bool f=0;
for(int i=0; i<a[root].size(); i++)
{
f=f|ifchild(a[root][i],an);
if(f)break;
}
return f;
}
void culre(ll root,ll sum)
{
re[root]=abs(sum-2*s[root]);
for(int i=0; i<a[root].size(); i++)
{
culre(a[root][i],sum);
}
return;
}
ll treefind(ll root,ll an)
{
for(int i=1; i<=n; i++)
{
re[i]=-1;
}
culre(root,s[root]);
ll mi=MAX;
ll sel;
for(int i=1; i<=n; i++)
{
if(re[i]!=-1)
{
if(re[i]<mi)
{
mi=re[i];
sel=i;
}
}
}
return sel;
}
bool par(int i)
{
if(i==1)return 0;
int j=p[i];
int l=a[j].size();
for(int k=0;k<l;k++)
{
if(a[j][k]==i)return 1;
}
return 0;
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
{
cin>>w[i];
}
for(int i=2; i<=n; i++)
{
cin>>p[i];
A[p[i]].push_back(i);
}
for(int ti=0; ti<m; ti++)
{
for(int i=0; i<=n; i++)
{
a[i]=A[i];
}
ll root=1,sel;
bool fout=0;
cin>>t;
if(a[t].size())fout=1;
while(1)
{
s[root]=su(root);
sel=treefind(root,t);
if(ifchild(sel,t))
{
if(sel==t)
{
if(a[t].size())
{
root=sel;
a[p[t]].clear();
fout=1;
cout<<sel<<' ';
}
else
{
if(fout)
{
cout<<endl;
}
else
cout<<t<<endl;
break;
}
}
else
{
root=sel;
cout<<sel<<' ';
}
}
else
{
ll cut=p[sel];
for(int i=0; i<a[cut].size();i++)
{
if(a[cut][i]==sel)
{
a[cut].erase(a[cut].begin()+i);
break;
}
}
if(cut==t)
{
if(a[t].size()==0&&par(t))fout=0;
}
cout<<sel<<' ';
}
}
}
return 0;
}