E. Split The Tree HDU - 6504

题目大意:给你一个树,每个节点上都有一个权值,把这棵树分成两棵树,问每一棵树的不同数值的个数和最大。

题解:首先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;
}

猜你喜欢

转载自blog.csdn.net/The_city_of_the__sky/article/details/89885564