题目链接Attachments - 2022 CCPC Henan Provincial Collegiate Programming Contest - Codeforces
这是一道河南省省赛的题,当时现场没写出来,思路完全没办法实现(虽然打星并且还是银),后来和学长交流思路,发现可以用树状数组和树的特性去写这道题.....,感觉思路十分清晰,于是就把这道题补了
题目
代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int h[N],e[N*2],ne[N*2],idx;
int tr[N*8];
int ans[N];
int n ;
int zi[N];
int lowbit(int x)
{
return x & -x ;
};
void add(int a, int b)
{
e[idx] = b , ne[idx] = h[a] , h[a] = idx ++ ;
}
void addd(int x ,int v)
{
for(int i = x; i <= n ; i += lowbit(i))tr[i] += v;
}
int summ(int x)
{
int res = 0 ;
for(int i = x ; i ; i -= lowbit(i))res += tr[i];
return res ;
}
void find(int u, int fa)
{
addd(a[u],1);
int now = summ(a[u]);
int res = 0;
int now2 ;
bool dt = false;
bool fres = false;
for(int i = h[u] ; ~i ; i = ne[i])
{
int j = e[i];
if(j == fa)continue;
find(j,u);
now2 = summ(a[u]);
// cout << u <<' '<< a[u] <<' '<<now <<' '<< now2 <<' '<<res<<endl;
if(now2 == now)continue;
else if(now2 > now)
{
if(now2 - now == a[u] - 1)
{
res = j;
fres = true;//表示找到了那个神奇的儿子。
}
else
{
dt = true;//表示改变的个数不够。
}
}
now = now2;//更新之后的当前区间的个数。
}
// cout <<"res == " << res <<endl;
if(a[u] == 1)
{
for(int i = h[u] ; ~i ; i = ne[i])
{
int j = e[i];
if(j == fa)continue;
if(!res)res = j;
else if(zi[res] < zi[j])res = j ;
}
if(fa == -1)ans[1] = zi[res];
else if(n - zi[u] > zi[res])
{
ans[1] = n - zi[u];
}
else ans[1] = zi[res];
}
else
{
//如果找到了那个神奇的儿子。
if(fres)ans[a[u]] = zi[res];
else if(dt)ans[a[u]] = 0;//如果当前儿子是分开的。
else ans[a[u]] = n - zi[u];//如果没有找到儿子。
}
}
int fee(int u ,int fa)
{
zi[u] = 1;
for(int i = h[u]; ~i ; i = ne[i])
{
int j = e[i];
if(j == fa)continue;
zi[u] += fee(j,u);
}
return zi[u];
}
int main()
{
ios :: sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(h,-1,sizeof h);
cin >> n;
int x;
for(int i = 1; i <= n ; i ++)
{
cin >> x;
a[i] = ++x;
}
int a, b ;
for(int i = 2; i <= n ; i++)
{
cin >> b ;
add(i,b);
add(b,i);
}
fee(1,-1);
find(1,-1);
for(int i = 1; i <= n ; i ++)
{
cout << ans[i] <<' ';
}
cout << n ;
cout <<endl;
}