题目链接:点击链接
题意:
给一棵n个点的树,点标号从1到n。有两种操作,操作1,将树上的某个点以及它的子孙都赋值为某个数;操作2,查询某个点的值。
思路:
做法一:
dfs。更新时,将目标节点更新就行,给节点记录一个时间戳。查询时,向上访问父亲节点,对比儿子节点和父亲节点的时间戳,如果父亲节点的时间戳晚于儿子节点,儿子的值等于父亲的值,反之亦然。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50005;
int cnt, cnt_now, ans;
int ord[maxn], fa[maxn], idx[maxn];
void init(){
memset(ord, -1, sizeof(ord));
memset(idx, -1, sizeof(idx));
memset(fa, -1, sizeof(fa));
cnt = 0;
}
void dfs(int x){
if(fa[x]==-1){
if(ord[x] > cnt_now){
cnt_now = ord[x];
ans = idx[x];
}
}
else{
if(ord[x] < ord[fa[x]]){
ord[x] = ord[fa[x]];
idx[x] = idx[fa[x]];
}
if(ord[x] > cnt_now){
cnt_now = ord[x];
ans = idx[x];
}
dfs(fa[x]);
}
}
int main(){
char opt[10];
int t, n, a, b, m, Case=0;
scanf("%d", &t);
while(t--){
init();
scanf("%d", &n);
for(int i=0; i<n-1; ++i){
scanf("%d%d", &a, &b);
fa[a] = b;
}
scanf("%d", &m);
printf("Case #%d:\n", ++Case);
for(int i=0; i<m; ++i){
scanf("%s", opt);
if(opt[0] == 'C'){
scanf("%d", &a);
cnt_now = -1; ans = -1;
dfs(a);
printf("%d\n", ans);
}
if(opt[0] == 'T'){
scanf("%d%d", &a, &b);
ord[a] = ++cnt;
idx[a] = b;
}
}
}
return 0;
}
做法二:
用dfs序建线段树。思路相当于,把当前节点管理所有儿子节点,转换为当前节点对应一条包含所有儿子的线段,
如何转换呢?dfs的时候,访问到当前节点x后,给节点x一个在线段树中的下标cnt,即节点x在线段树中对应的起点,记录为L[x] =cnt,继续深入,重复之前的操作,cnt不断加1。dfs再次返回到x时,我们知道节点x所管理的儿子在线段树中的终点为cnt,记录为R[x] = cnt,那么x节点对应的线段在线段树中为[L[x], R[x]],这样就完成了树到线段树的映射。
之后就是对应的区间懒惰更新,单点查询。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 50005;
int cnt;
int L[maxn], R[maxn];
int tree[maxn<<2];
int lazy[maxn<<2];
int pre[maxn];
vector<int> edges[maxn];
void init(int n){
cnt = 0;
memset(pre, 0, sizeof(pre));
memset(tree, -1, sizeof(tree));
memset(lazy, -1, sizeof(tree));
for(int i=1; i<=n; ++i) edges[i].clear();
}
void dfs(int rt){
L[rt] = ++cnt;
for(int i=0; i<edges[rt].size(); ++i){
dfs(edges[rt][i]);
}
R[rt] = cnt;
}
void pushdown(int rt){
if(lazy[rt]!=-1){
tree[rt<<1] = tree[rt<<1|1] = tree[rt];
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
}
void update(int rt, int a, int b, int l, int r, int x){
if(a<=l && r<=b){
tree[rt] = lazy[rt] = x;
}
else{
pushdown(rt);
int mid = (l+r)>>1;
if(a<=mid) update(rt<<1, a, b, l, mid, x);
if(mid<b) update(rt<<1|1, a, b, mid+1, r, x);
}
}
int query(int rt, int idx, int l, int r){
if(l==r && l==idx){
return tree[rt];
}
else{
int mid = (l+r)>>1;
pushdown(rt);
if(idx<=mid) return query(rt<<1, idx, l, mid);
if(mid<idx) return query(rt<<1|1, idx, mid+1, r);
}
}
int main(){
char opt[10];
int t, n, a, b, m, Case=0;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
init(n);
for(int i=0; i<n-1; ++i){
scanf("%d%d", &a, &b);
edges[b].push_back(a);
++pre[a];
}
for(int i=1; i<=n; ++i){
if(pre[i]==0){
dfs(i);
break;
}
}
scanf("%d", &m);
printf("Case #%d:\n", ++Case);
for(int i=0; i<m; ++i){
scanf("%s", opt);
if(opt[0] == 'C'){
scanf("%d", &a);
printf("%d\n", query(1, L[a], 1, cnt));
}
if(opt[0] == 'T'){
scanf("%d%d", &a, &b);
update(1, L[a], R[a], 1, cnt, b);
}
}
}
return 0;
}