题意:
一颗n个节点n-1条边的树,T X Y表示给节点x及其子树涂色,C X表示询问节点X的颜色(初始都是-1)
思路:(不要漏写运算符了)
vis标记入度大于等于1的点,未标记的点就是根结点。
dfs序可以把子树映射到连续的区间上,维护每个节点的dfs序以及子树最后一个节点的dfs序。
区间修改单点查询,修改因为是覆盖的,所以不需要lazy标记和向上更新信息,查询时,如果当前区间被涂色了,就输出,反之继续查询子区间,直到
Code:
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std; typedef long long ll; const int maxn=5e4+7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int head[maxn],to[maxn],Next[maxn],tot; int dfn[maxn],ri[maxn],cnt,tree[maxn<<2]; bool vis[maxn]; inline void add(int x,int y) { to[++tot]=y; Next[tot]=head[x]; head[x]=tot; } void dfs(int x) { dfn[x]=++cnt; for(int i=head[x],y;i;i=Next[i]) dfs(to[i]); ri[x]=cnt; } inline void pushdown(int rt) { if(~tree[rt]) { tree[rt<<1]=tree[rt<<1|1]=tree[rt]; tree[rt]=-1; } } inline void update(int x,int y,int val,int l,int r,int rt) { if(x<=l&&y>=r) { tree[rt]=val; return; } pushdown(rt); int mid=l+r>>1; if(x<=mid) update(x,y,val,l,mid,rt<<1); if(y>mid) update(x,y,val,mid+1,r,rt<<1|1); } inline int query(int x,int l,int r,int rt) { if(~tree[rt]) return tree[rt]; if(l==r) return -1; int mid=l+r>>1; if(x<=mid) return query(x,l,mid,rt<<1); else return query(x,mid+1,r,rt<<1|1); } int main() { char s; int t=read(),n,m,x,y,cas=0; while(t--) { n=read(); tot=cnt=0; memset(vis,true,sizeof vis); memset(head,0,sizeof head); memset(tree,-1,sizeof tree); for(int i=2;i<=n;++i) { x=read(),y=read(); vis[x]=false; add(y,x); } for(int i=1;i<=n;++i) if(vis[i]) { dfs(i); break; } m=read(); printf("Case #%d:\n",++cas); while(m--) { scanf(" %c",&s); if(s=='T') { x=read(),y=read(); update(dfn[x],ri[x],y,1,n,1); } else { x=read(); printf("%d\n",query(dfn[x],1,n,1)); } } } return 0; }