Assign the task
题意:
一颗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;
} [kuangbin带我飞]专题七 线段树 文章被收录于专栏
线段树入门到进阶 树不能只记得它的样子,要清楚它的性质,比如相邻点的关系

