题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974
解题思路:
将所有的关系建树,每次修改每一节点的同时对其所有子节点修改。
我们可以利用dfs序。
记录某一个点进入(开始遍历子节点)的顺序,出去(所有子节点全部遍历)的顺序

如图,其中一种dfs序为1 2 4 4 5 5 2 3 3 1,在一个节点这对位置中间都是都是这个节点的子节点。
建线段树。
in[x],out[x]表示x节点进出在dfs序中的位置,每次单点修改相当于[ in[x],out[x] ]的区间修改。
询问就so easy啦。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
using namespace std;
const int N = 5e4+5;
int tree[N<<3];///N*2 *4
int in[N],out[N],tot;///dfs进的位置,出的位置
struct node{///链式前向星建边
int last,to;
}edge[N];
int head[N],id;
void add(int u,int v){edge[id].to = v; edge[id].last = head[u]; head[u] = id++;}
void dfs(int now){
in[now] = ++tot;//printf("in[%d]=%d\n",now,in[now]);
for (int i=head[now];i!=0;i=edge[i].last){
int v = edge[i].to;
dfs(v);
}
out[now] = ++tot;//printf("out[%d]=%d\n",now,out[now]);
}
void push_up(int rt){
if (tl==tr) tree[rt] = tl;
else tree[rt] = -2;///表示区间有不同颜色,初始-1也当做一种颜色
}
void push_down(int rt){
tl = tr = tree[rt];
}
void update(int L,int R,int x,int rt,int l,int r){
if (L<=l && r<=R){
tree[rt] = x;
return ;
}
mid;
if (tree[rt]>=0) push_down(rt);///区间下放,-1不用,-1的话子节点肯定是-1
if (L<=m) update(L,R,x,lson);
if (R>m) update(L,R,x,rson);
push_up(rt);
}
int query(int p,int rt,int l,int r){
if (tree[rt]>=-1){///只要不是-2,这个区间都是一种颜色。
return tree[rt];
}
if (l==r){
return tree[rt];
}
mid;
if (p<=m) return query(p,lson);
else return query(p,rson);
}
void build(int rt,int l,int r){
if (l==r){
tree[rt] = -1;
return ;
}
mid;
build(lson);
build(rson);
push_up(rt);
}
int main()
{
int T;
scanf("%d",&T);
for (int sb = 1;sb<=T;sb++){
id = 1;
tot = 0;
memset(head,0,sizeof head);
memset(in,0,sizeof in);///这个数组还用于统计入度找root节点,所以初始化
printf("Case #%d:\n",sb);
int n;
scanf("%d",&n);
for (int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(v,u);
in[u]++;
}
int root;
for (int i=1;i<=n;i++)///找root节点
if (in[i]==0){
root = i;
break;
}
dfs(root);
build(1,1,tot);
int q,x,y;
char op[2];
scanf("%d",&q);
while (q--){
scanf("%s",op);
if (op[0]=='C'){
scanf("%d",&x);
printf("%d\n",query(in[x],1,1,tot));
}
else {
scanf("%d %d",&x,&y);
update(in[x],out[x],y,1,1,tot);
}
}
}
return 0;
}
博客给出HDU 3974题目的链接,介绍解题思路。先将所有关系建树,修改节点时对其子节点修改,利用dfs序记录节点进出顺序,建线段树,单点修改相当于区间修改,最后给出解题代码。
1570

被折叠的 条评论
为什么被折叠?



