修改一个点,实际上等价于同时修改一些点。而将一棵树深度遍历所得到的序列中,根节点相同的节点的标号刚好是相邻的。
根据这个性质,用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; }