AmazingCounters.com

[BZOJ]2017省队十连测推广赛1 T2.七彩树

题目大意:给你一棵n个点的树,每个点有颜色,m次询问,每次询问一个点x的子树内深度不超过depth[x]+d的节点的颜色数量,强制在线。(n,m<=100000,多组数据,保证n,m总和不超过500000)

思路:若不考虑深度限制,我们可以先给每个点赋点权1,再把每种颜色的节点按dfs序排序后相邻的节点的LCA的点权减1,每次求子树和即可回答询问,若有限制深度,我们可以按深度顺序把点一个个加入树中,每种颜色用个set维护,强制在线只要把求子树和的线段树可持久化就可以了,总复杂度O(nlogn)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 100000
#define K 17
#define ND 8000000
struct edge{int nx,t;}e[MN+5];
int h[MN+5],en,c[MN+5],d[MN+5],l[MN+5],r[MN+5],cnt,fa[K][MN+5],p[MN+5],rt[MN+5],tn;
class stcmp{public:inline bool operator()(int a,int b){return l[a]<l[b];}};
set<int,stcmp> st[MN+5];
set<int,stcmp>::iterator x,y,z;
struct node{int l,r,s;}t[ND+5];
int renew(int x,int l,int r,int k,int z)
{
    int p=++tn,mid=l+r>>1;
    if(l==r)return t[p]=(node){0,0,t[x].s+z},p;
    if(k<=mid)return t[p]=(node){renew(t[x].l,l,mid,k,z),t[x].r,t[x].s+z},p;
    return t[p]=(node){t[x].l,renew(t[x].r,mid+1,r,k,z),t[x].s+z},p;
}
int query(int x,int l,int r,int L,int R)
{
    if(l==L&&r==R)return t[x].s;
    int mid=l+r>>1;
    if(R<=mid)return query(t[x].l,l,mid,L,R);
    if(L>mid)return query(t[x].r,mid+1,r,L,R);
    return query(t[x].l,l,mid,L,mid)+query(t[x].r,mid+1,r,mid+1,R);
}
inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
void dfs(int x)
{
    l[x]=++cnt;
    for(int i=h[x];i;i=e[i].nx)d[e[i].t]=d[x]+1,dfs(e[i].t);
    r[x]=cnt;
}
bool cmp(int a,int b){return d[a]<d[b];}
int lca(int x,int y)
{
    int dx=d[x]-d[y],i;
    if(dx<0)dx=-dx,swap(x,y);
    for(i=0;dx;dx>>=1,++i)if(dx&1)x=fa[i][x];
    if(x==y)return x;
    for(i=K;i--;)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}
int main()
{
    int T,n,m,i,j,t;
    for(T=read();T--;)
    {
        n=read();m=read();
        for(i=1;i<=n;++i)c[i]=read(),p[i]=i,st[i].clear();
        memset(h,t=tn=en=cnt=0,sizeof(int)*(n+1));
        for(i=2;i<=n;++i)ins(fa[0][i]=read(),i);
        for(i=1;i<K;++i)for(j=1;j<=n;++j)fa[i][j]=fa[i-1][fa[i-1][j]];
        dfs(1);sort(p+1,p+n+1,cmp);
        for(i=1;i<=n;++i)
        {
            t=renew(t,1,n,l[p[i]],1);
            st[c[p[i]]].insert(p[i]);
            x=y=z=st[c[p[i]]].find(p[i]);--x;++z;
            if(y!=st[c[p[i]]].begin()&&z!=st[c[p[i]]].end())t=renew(t,1,n,l[lca(*x,*z)],1);
            if(y!=st[c[p[i]]].begin())t=renew(t,1,n,l[lca(*x,*y)],-1);
            if(z!=st[c[p[i]]].end())t=renew(t,1,n,l[lca(*y,*z)],-1);
            rt[d[p[i]]]=t;
        }
        for(t=0;m--;)
        {
            i=read()^t;j=read()^t;
            printf("%d\n",t=query(rt[d[i]+j>d[p[n]]?d[p[n]]:d[i]+j],1,n,l[i],r[i]));
        }
    }
}

 

posted on 2017-03-13 15:04  ditoly  阅读(182)  评论(0编辑  收藏  举报