题目大意:给你一个树,每个节点上都有一个权值,把这棵树分成两棵树,问每一棵树的不同数值的个数和最大。
题解:首先dfs序,如果查询所有子树,会把两棵树分成三个区间,就不能查询第二课树的不同数值的个数,所以复制此序列放在第一次的后面,因为是离线的,可以使用树状数组维护区间不同数值的个数,对于当前r位置把此位置加上树状数组中,如果前面有相同的值,那么把前面的那个位置删除,然后查询此r位置的l就能找到不同数值的个数,所以要预先处理好查询,以r排序。(也可以使用主席树,但是必须写的非常优秀,才能卡时间过,树状数组快了三倍,所以树状数组真的很优秀)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int tot;int s[maxn*2];
int lowbit(int x){
return x&-x;
}
void add(int n,int num)
{
while(n<=tot)
{
s[n]+=num;
n+=lowbit(n);
}
}
int query(int x)
{
int ans=0;
while(x>0)
{
ans+=s[x];
x-=lowbit(x);
}
return ans;
}
int xu[maxn],vi,vis[maxn],pp[maxn],ed[maxn],a[maxn];
vector<int>g[maxn];struct node{int l,r,num,id;}xx[maxn*2];
void dfs(int now,int fath)
{
xu[++vi]=now;int x=vi;
int len=g[now].size();
for(int i=0;i<len;i++)
{
int v=g[now][i];
if(v!=fath) dfs(v,now);
}
ed[x]=vi;
}
int cmp(node p,node q)
{
if(p.r==q.r) return p.l<q.l;
return p.r<q.r;
}
int main()
{
int n,u,v;
while(~scanf("%d",&n))
{
for(int i=0;i<=n;i++) g[i].clear();
memset(vis,0,sizeof(vis));
memset(pp,0,sizeof(pp));
memset(s,0,sizeof(s));
tot=2*n;
for(int i=2;i<=n;i++)
{
scanf("%d",&u);
g[u].push_back(i);
g[i].push_back(u);
}
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
vi=0; dfs(1,0);
for(int i=1;i<=n;i++)
{
xx[i].l=i;xx[i].r=ed[i];
xx[i+n].l=ed[i]+1; xx[i+n].r=i-1+n;
xx[i].id=xx[i+n].id=i;
}
sort(xx+1,xx+1+2*n,cmp);
int l=1;
for(int i=1;i<=n;i++)
{
add(i,1);
if(vis[a[xu[i]]]!=0) add(vis[a[xu[i]]],-1);
vis[a[xu[i]]]=i;
while(l<=2*n)
{
if(xx[l].r==i) xx[l].num=query(xx[l].r)-query(xx[l].l-1),l++;
else break;
}
}
for(int i=n+1;i<=2*n;i++)
{
add(i,1);
if(vis[a[xu[i%n]]]!=0) add(vis[a[xu[i%n]]],-1);
vis[a[xu[i%n]]]=i;
while(l<=2*n)
{
if(xx[l].r==i) xx[l].num=query(xx[l].r)-query(xx[l].l-1),l++;
else break;
}
}
for(int i=1;i<=2*n;i++)
{
pp[xx[i].id]+=xx[i].num;
}
// for(int i=1;i<=2*n;i++) cout<<xx[i].num<<' '<<xx[i].r<<endl;
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,pp[i]);
printf("%d\n",ans);
}
return 0;
}