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;}