修改一个点,实际上等价于同时修改一些点。而将一棵树深度遍历所得到的序列中,根节点相同的节点的标号刚好是相邻的。
根据这个性质,用dfs对每个节点重新编号,修改一个点就变成了修改一个连续的区间。本题就变成了区间修改单点查询的线段树问题。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#include <vector>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int a[50005*4];
int add[50005*4];
bool root[50005];
int N,M;
int st[50005];
int ed[50005];
int Hs[50005];
int Num=0;
vector<int> G[50005];
void dfs(int u){
Num++;
Hs[u]=Num;
st[u]=Num;
for(int i=0;i<G[u].size();i++){
dfs(G[u][i]);
}
ed[u]=Num;
}
void pushdown(int rt){
if(add[rt]!=-1){
add[rt<<1]=add[rt];
add[rt<<1|1]=add[rt];
a[rt<<1]=a[rt<<1|1]=add[rt];
add[rt]=-1;
}
}
void update(int L,int R,int l,int r,int rt,int n){
pushdown(rt);
if(L<=l&&R>=r){
add[rt]=n;
a[rt]=n;
return ;
}
int mid=(l+r)>>1;
if(mid>=L) update(L,R,lson,n);
if(mid<R) update(L,R,rson,n);
}
int query(int n,int l,int r,int rt){
pushdown(rt);
if(l==r){
return a[rt];
}
int mid=(l+r)>>1;
if(mid>=n) return query(n,lson);
else return query(n,rson);
}
int main(){
int T;
int kase=1;
scanf("%d",&T);
while(T--){
memset(a,-1,sizeof(a));
memset(add,-1,sizeof(add));
memset(root,0,sizeof(root));
memset(Hs,0,sizeof(Hs));
Num=0;
scanf("%d",&N);
for(int i=0;i<=N;i++){
G[i].clear();
}
for(int i=0;i<N-1;i++){
int u,v;
scanf("%d%d",&u,&v);
G[v].push_back(u);
root[u]=1;
}
for(int i=1;i<=N;i++){
if(!root[i]){
dfs(i);
break;
}
}
scanf("%d",&M);
printf("Case #%d:\n",kase++);
for(int i=0;i<M;i++){
char ist[2];
int x,y;
scanf("%s",ist);
if(ist[0]=='C'){
scanf("%d",&x);
printf("%d\n",query(Hs[x],1,Num,1));
}
else{
scanf("%d%d",&x,&y);
update(st[x],ed[x],1,Num,1,y);
}
}
}
return 0;
}
本文介绍了一种利用线段树解决区间修改单点查询问题的方法,并通过实例展示了如何将修改操作转化为区间修改,简化了复杂度,提高了效率。
901

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



