Assign the task(dfs序+线段树)

题目传送门

Assign the task

题目大意

给你一棵树,共n个结点,每个结点具有一个颜色,可以对结点进行染色和查询
共n-1条边,分N-1行分别包含两个整数u和v,表示v是u的父节点
然后有m次操作
若为染色操作则输入“T x k”
若为查询操作则输入“C x”

思路

首先可以用dfs序将无根树区间化,即可以求出每个节点的管辖区间
然后就是区间修改,单点查询即可,维护每个点的值即可

AC Code

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
#define debug(a) cout<<#a<<"="<<a<<endl;
#define INF 0x3f3f3f3f
const int N=5e4 +9;
int T, n, u, v, m, x, y, res;
int lid[N], rid[N], vis[N];
char op;
vector<int>g[N];
struct segtree{
    int v, lazy;
}tr[N<<2];

inline void dfs(int v){
    lid[v]=++res;
    for(auto u:g[v])    dfs(u);
    rid[v]=res;
}

inline int lc(int p) {return p<<1;}
inline int rc(int p) {return p<<1|1;}
inline void build(int p, int l, int r){ 
    tr[p].v=-1;
    tr[p].lazy=0;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(lc(p), l, mid);
	build(rc(p), mid+1, r);
}
inline void f(int p, int k){
	tr[p].v=k;
    tr[p].lazy=k;
}
inline void push_down(int p){
	f(lc(p), tr[p].lazy);
	f(rc(p), tr[p].lazy);
	tr[p].lazy=0;
}
inline void updata(int p, int l, int r, int x, int y, int k){
	if(x>r || y<l)	return ;
	if(l<=x && y<=r){
        tr[p].v=k;
        tr[p].lazy=k;
		return ;
	}
	if(tr[p].lazy) push_down(p);
	int mid=(x+y)>>1;
	updata(lc(p), l, r, x, mid, k);
	updata(rc(p), l, r, mid+1, y, k);
}

inline int query(int p, int d, int x, int y){
	if(x==y) return tr[p].v;
    if(tr[p].lazy) push_down(p);
    int mid=(x+y)>>1;
    if(d<=mid) return query(lc(p), d, x, mid);
    else  return query(rc(p), d, mid+1, y);
}
signed main(){
    cin>>T;
    int count=0;
    while(T--){
        cin>>n;
        build(1,1,n);
        for(int i=1; i<=n; i++) g[i].clear(), vis[i]=0;
        res=0;
        for(int i=1; i<=n-1; i++){
            cin>>u>>v;
            g[v].push_back(u);
            vis[u]=1;
        }
        for(int i=1; i<=n; i++) if(!vis[i]) dfs(i);
        cin>>m;
        printf("Case #%d:\n", ++count);
        for(int i=1; i<=m; i++){
            cin>>op;
            if(op=='C'){
                cin>>x;
                cout<<query(1,lid[x],1,n)<<endl;
            }
            else if(op=='T'){
                cin>>x>>y;
                updata(1,lid[x],rid[x],1,n,y);
            }
        }
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值