HDU - 5709 Claris Loves Painting (线段树合并+动态开点)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/82318008

Claris Loves Painting

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 524    Accepted Submission(s): 148


 

Problem Description

Claris loves painting very much, so he painted a tree with beautiful colors.

The tree is a rooted tree with n nodes which are conveniently labeled by 1,2,...,n. Its root is the 1-st node, and the i-th node is painted with color ci. If ci=cj, then we think these two nodes have the same color.

We define depthi as the distance between the i-th node and the root, and simply, the distance between two adjacent nodes is always 1.

Standing in front of this beautiful tree, Claris comes up with m questions.
In each question, there are two integers x and d, which means that Claris wants to know the number of different kinds of colors occur in S, where S={v|v in x′s subtree and depthv≤depthx+d}.

 

Input

The first line of the input contains an integer T(1≤T≤500), denoting the number of test cases.

In every test case, there are two integers n(1≤n≤100000) and m(1≤m≤100000) in the first line, denoting the number of nodes and queries.
The second line contains n integers, the i-th integer ci(1≤ci≤n) denotes the color of the i-th node.
The third line contains n−1 integers, the i-th integer fi+1(1≤fi<i) denotes the father of the i+1-th node.
In the following m lines, each line contains two integers x(1≤x≤n) and d(0≤d<n), denoting each query.

The input has been encoded, if you read x and d, the real x and d are x⊕last and d⊕last, where last is the answer of the previous query and ⊕ means bitwise exclusive-or.

Notice : 
If it is the first query in this test case, then last=0.
It is guaranteed that ∑n≤500000 and ∑m≤500000.

 

Output

For each query output a single integer in a line, denoting the answer.

 

Sample Input

 

1 5 8 1 3 3 2 2 1 1 3 3 1 0 0 0 3 0 1 3 2 1 2 0 6 2 4 1

 

Sample Output

 

1 2 3 1 1 2 1 1

 

Source

"巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场

 

Recommend

liuyiding

 

题意:一棵有根树,树上每一个点有可能相同的颜色,现在要求回答若干个询问,求在u的子树内与u相距不超过d的点有多少种颜色。强制在线。

解题思路:线段树合并,这里用来锻炼下线段树合并的动态开点写法,同时熟悉下线段树的结构体写法。

具体思路参考博客:http://sycstudio.com/archives/513

#include<iostream>
#include<string.h>
#include<queue>
#include<bitset>
#include<vector>
using namespace std;
typedef long long ll;
const int MAXN=100105;
int N,M;
vector<int> G[MAXN];
int C[MAXN];
int dep[MAXN];

//学习一下结构体写法……
struct Node{
    int ls,rs,val;
}node[MAXN*110];
int tot;

int root1[MAXN];//每个深度的颜色数
int root2[MAXN];//每个颜色最浅的那个位置

int update(int P,int C,int l,int r,int rt){
    int nrt=++tot;
    node[nrt].val=node[rt].val+C;//由于第二棵线段树只关心叶子结点信息,所以用一个update实现就好了
    if(l==r)
        return nrt;
    int m=(l+r)/2;
    if(P<=m){
        node[nrt].ls=update(P,C,l,m,node[rt].ls);
        node[nrt].rs=node[rt].rs;
    }
    else{
        node[nrt].rs=update(P,C,m+1,r,node[rt].rs);
        node[nrt].ls=node[rt].ls;
    }
    return nrt;
}

int merge1(int r1,int r2,int l,int r){
    if(r1==0||r2==0)
        return r1+r2;
    int nrt=++tot;//记得新建节点
    node[nrt].val=node[r1].val+node[r2].val;//直接合并
    if(l==r)
        return nrt;
    int m=(l+r)/2;
    node[nrt].ls=merge1(node[r1].ls,node[r2].ls,l,m);
    node[nrt].rs=merge1(node[r1].rs,node[r2].rs,m+1,r);
    return nrt;
}

int merge2(int r1,int r2,int l,int r,int u){
    if(r1==0||r2==0)
        return r1+r2;
    int nrt=++tot;

    if(l==r){
        //根据小的那个来更新
        if(node[r1].val>node[r2].val){
            node[nrt].val=node[r2].val;
            root1[u]=update(node[r1].val,-1,1,N,root1[u]);
        }
        else{
            node[nrt].val=node[r1].val;
            root1[u]=update(node[r2].val,-1,1,N,root1[u]);
        }
        return nrt;
    }
    int m=(l+r)/2;
    node[nrt].ls=merge2(node[r1].ls,node[r2].ls,l,m,u);
    node[nrt].rs=merge2(node[r1].rs,node[r2].rs,m+1,r,u);
    return nrt;
}

int query(int P,int l,int r,int rt){
    if(!rt)
        return 0;
    if(r<=P)
        return node[rt].val;
    int m=(l+r)/2;
    int ans=query(P,l,m,node[rt].ls);
    if(P>=m+1)
        ans+=query(P,m+1,r,node[rt].rs);
    return ans;
}



void dfs(int x){
    root1[x]=update(dep[x],1,1,N,0);
    root2[x]=update(C[x],dep[x],1,N,0);
    for(int i=0;i<G[x].size();i++){
        int v=G[x][i];
        dep[v]=dep[x]+1;
        dfs(v);
        root1[x]=merge1(root1[x],root1[v],1,N);
        root2[x]=merge2(root2[x],root2[v],1,N,x);
    }
}


int main(){
    int T;
    scanf("%d",&T);
    for(int qqq=1;qqq<=T;qqq++){
        scanf("%d%d",&N,&M);

        for(int i=1;i<=N;i++){
            scanf("%d",&C[i]);
            G[i].clear();
        }
        int x;
        for(int i=2;i<=N;i++){
            scanf("%d",&x);
            G[x].push_back(i);
        }

        tot=0;
        node[0].ls=node[0].rs=node[0].val=0;
        dep[1]=1;
        dfs(1);

        int lastans=0;
        for(int i=1;i<=M;i++){
            int u,d;
            scanf("%d%d",&u,&d);
            u^=lastans;
            d^=lastans;
            printf("%d\n",lastans=query(min(dep[u]+d,N),1,N,root1[u]));
        }

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/82318008