因为刚学线段树,这个题做的时候费了不少劲,尤其是树的序列化,看了题解才知道:
(对于更新一个结点及其子节点的操作,我们在树上没办法直接操作,我们可以考虑利用dfs给所有点编一个开始点号和结束点号,这样在开始和结束点号间的点号都是该结点的子结点,所以只要对这个区间的数操作即可完成对所有子节点的操作,就成功将树给序列化了,然后进行正常线段树操作就行,访问的话访问l或者r查询其标记值即可。)
然后找到祖先节点,dfs搜出两个序列,然后开始线段树操作,以后基本上就正常了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=50005;
int t,n,m,u,v,cnt,st[maxn],en[maxn],vis[maxn],tag[maxn*4];
char p;
vector<int>a[maxn];
void init()
{
memset(vis,0,sizeof(vis));
memset(tag,-1,sizeof(tag));
cnt=0;
}
void dfs(int x)
{
st[x]=(++cnt);
for(int i=0; i<a[x].size(); i++)
dfs(a[x][i]);
en[x]=(++cnt);
}
void pushdown(int k)
{
if(tag[k]!=-1)
{
tag[k*2]=tag[k];
tag[k*2+1]=tag[k];
tag[k]=-1;
}
}
void updateqj(int k,int l,int r,int x,int y,int p)
{
if(l>=x&&r<=y)
{
tag[k]=p;
return;
}
pushdown(k);
int mid=(l+r)/2;
if(x<=mid)
updateqj(k*2,l,mid,x,y,p);
if(y>mid)
updateqj(k*2+1,mid+1,r,x,y,p);
}
int query(int k,int l,int r,int x)
{
if(l==r)
return tag[k];
pushdown(k);
int mid=(l+r)/2;
if(x<=mid)return query(k*2,l,mid,x);
else return query(k*2+1,mid+1,r,x);
}
int main()
{
int ca=0;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1; i<n; i++)
{
scanf("%d%d",&u,&v);
a[v].push_back(u),vis[u]=1;
}
for(int i=1; i<=n; i++)
if(!vis[i])
{
dfs(i);
break;
}
scanf("%d",&m);
printf("Case #%d:\n",++ca);
for(int i=0;i<m;i++){
char ch;
int p,o;
scanf(" %c%d",&ch,&p);
if(ch=='C')printf("%d\n",query(1,1,cnt,en[p]));
if(ch=='T'){
scanf("%d",&o);
updateqj(1,1,cnt,st[p],en[p],o);
}
}
for(int i=1;i<=n;i++)a[i].clear();
}
return 0;
}