dfs序+线段树

传送门
现有一棵树,有以下操作: 1. 节点x及其所有子孙颜色都变更为k。 2. 要求你回答节点x的颜色。 初始所有点都没有染色。

Input

第一行一个整数T(T <= 10),表示样例组数。
对于每个测试样例:
第一行一个整数n(n <= 5e4),表示树的节点个数。
接下来n行,每行两个整数u, v(1 <= u, v <= n),表示树中u的父节点是v。
接下来一行一个整数q(q <= 5e4),表示询问数。
接下来q行:
若为染色操作则输入“T x k”,若为查询操作则输入“C x”,(1 <= x <= n, 0 <= y <= 1e9)。

Output

每个测试样例首先输出一行"Case #x:",其中x为当前样例编号。
对于每个询问操作输出一个整数,表示当前节点的颜色,若还未染色则输出-1。

Sample Input

1 
5 
4 3 
3 2 
1 3 
5 2 
5 
C 3 
T 2 1
 C 3 
T 3 2 
C 3

Sample Output

Case #1:
-1 
1 
2
在做这个题之前要先知道什么是dfs序
在网上盗了个图

 

在dfs序的两个数组s[]和e[],就是s[p]是p这个节点的孩子的开始e[p]是p这个节点的孩子的结束
s[p]--e[p]就是所有孩子(包括自子)的所有下标(注意他的下标是被重新定义的)
要先找到他的入口就是入度为0的点
代码实现就是用dfs
void dfs(int u){
    s[u]=++index;
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].to;
        dfs(v);
    }
    e[u]=index;
}

dfs序

参考博客

把这个题dfs序求出来之后就是线段树的区间修改,单点查询了

在这个题中样例中dfs序为

 

 

注意这个下标被重构了

注意如果是这样的话”

void dfs(int u){
    in[u]=++idx;
    for(int i=head[u];~i;i=ne[i]){
        int v=e[i];
        dfs(v);
    }
    out[u]=++idx;
}

他的结果是这样的:

 

 

 

 

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
const int maxn=1e6+100;
typedef long long ll;
struct node{
    int l,r;
    int val;
}t[maxn]; 
struct tu{
    int next;
    int to;
}edge[maxn];
int head[maxn],cnt;
int index=0;
int s[maxn],e[maxn];
bool vis[maxn];
void add(int u,int v){ 
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u){//求dfs序 
    s[u]=++index;
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].to;
        dfs(v);
    }
    e[u]=index;
}
void jianshu(int p,int l,int r){
    t[p].l=l;
    t[p].r=r;
    t[p].val=-1;
    if(l==r){
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    jianshu(2*p,l,mid);
    jianshu(2*p+1,mid+1,r);
}
void push_up(int p){
    if(t[p].val>=0){
        t[2*p].val=t[p].val;
        t[2*p+1].val=t[p].val;
        t[p].val=-1;
    }
}
void update(int p,int l,int r,int k){
    if(l<=t[p].l&&t[p].r<=r){
        t[p].val=k;
        return ;
    }
    push_up(p); 
    if(l<=t[2*p].r){
        update(2*p,l,r,k);
    }
    if(r>=t[2*p+1].l){
        update(2*p+1,l,r,k);
    }
}
int query(int p,int x){
    if(t[p].l==t[p].r){
        return t[p].val;
    }
    push_up(p);
    if(x<=t[2*p].r){//单点 
        return query(2*p,x);
    } 
    else{
        return query(2*p+1,x);
    }
}
int main(){
    int t;
    cin>>t;
    int kase=0;
    while(t--){
        memset(head,-1,sizeof(head));
        memset(vis,false,sizeof vis);
        cnt=0;
        index=0;
        int n;
        cin>>n;
        int u,v;
        for(int i=1;i<=n-1;i++){
            scanf("%d%d",&u,&v);//v是父节点 
            add(v,u);
            vis[u]=true;
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){//找起点 
                dfs(i);
                break;
            }
        }
        jianshu(1,1,n); 
        char str[10];
        int x,k; 
        int m;
        scanf("%d",&m);
        printf("Case #%d:\n",++kase);
        for(int i=1;i<=m;i++){
            scanf("%s",str);
            if(str[0]=='C'){
                scanf("%d",&x);
                int ans=query(1,s[x]);
                printf("%d\n",ans); 
            }
            else if(str[0]=='T'){
                scanf("%d%d",&x,&k);
                update(1,s[x],e[x],k);
            }
        }
        
    }
} 

 

 

 

void dfs(int u){in[u]=++idx;for(int i=head[u];~i;i=ne[i]){int v=e[i];dfs(v);}out[u]=++idx;}

posted @ 2020-11-06 10:20  lipu123  阅读(361)  评论(0)    收藏  举报