CF--- PROBLEM 620 E 【思维 + DFS序 + 二进制状态】

传送门
//题意: 对于一棵树以1为根的树, 每个结点有一种颜色. 现在有两种操作.
1 x y 把以x为根节点的子树中的所有节点染成颜色y
2 x 询问以x为根节点的子树中有多少种颜色的节点
//思路: 很明显的DFS序, 需要考虑几点, 涉及到线段树的区间修改. 然后就是颜色的计数, 由于颜色最多60种, 那么用long long 的二进制来表示它的颜色. 这样再pushup时直接左右子树或起来就行. 注意一个坑点就是在DFS序中的线段树描述的是各个节点的序了!!! 不再是每一个节点本身. 所以在build中, tree[id].val = a[dfsxu[l]] (dfsxu表示的是当前节点在dfs序中代表的节点!!!), 而不是a[l] !!! 这个BUG调了我好久. 要多做做这方面的题啊.

AC Code

/** @Cain*/
const int maxn = 4e5+5;
int cas=1;
ll a[maxn];
int dfs_xx[maxn];
struct node{
    int tl, tr; ll val, maxx, lazy;
    void fun(ll tmp) {      //如果是直接加值就用 +=
        lazy = tmp;
        val = 1ll<<(tmp-1);
        //maxx = tmp;
    }
} tree[maxn*4];

void pushup(int id)
{
    tree[id].val = tree[id<<1].val|tree[id<<1|1].val;
    //tree[id].maxx = max(tree[id<<1].maxx,tree[id<<1|1].maxx);
}

void pushdown(int id)
{
    if(tree[id].lazy){
        tree[id<<1].fun(tree[id].lazy);
        tree[id<<1|1].fun(tree[id].lazy);
        tree[id].lazy = 0;
    }
}

void build(int id,int l,int r)
{
    tree[id].tl = l; tree[id].tr = r; tree[id].lazy = 0;
    if(l == r){
        tree[id].val = a[dfs_xx[l]];  //这是一个坑点啊.就如上面我所说.
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    pushup(id);
}

void update(int id,int st,int ed,int val)
{
    int l=tree[id].tl, r=tree[id].tr;
    if(st <= l && r <= ed){
        tree[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(st <= mid) update(id<<1,st,ed,val);
    if(ed > mid) update(id<<1|1,st,ed,val);
    pushup(id);
}

ll query(int id,int ql,int qr)
{
    int l = tree[id].tl , r = tree[id].tr;
    if(ql <= l && r <= qr) return tree[id].val;
    pushdown(id);
    int mid = (l+r) >> 1 ;
    ll res = 0;
    if(ql <= mid) res |= query(id<<1,ql,qr);
    if(qr > mid) res |= query(id<<1|1,ql,qr);
    return res;
}

struct edge
{
    int to,next;
    ll w;
}s[maxn];
int cnt,ti,head[maxn];
int p1[maxn],p2[maxn];
void add(int u,int v,ll w)
{
    s[cnt] = (edge){v,head[u],w};
    head[u] = cnt++;
}

void dfs_id(int u,int fa)
{
    p1[u] = ++ti;
    dfs_xx[ti] = u;
    for(int i=head[u]; ~i ; i = s[i].next){
        int to = s[i].to;
        if(fa == to) continue;
        dfs_id(to,u);
    }
    p2[u] = ti;
}

void solve()
{
    int n,q;
    ll b[50];
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        ll u; scanf("%lld",&u);
        b[i] = u;
        a[i] = 1ll<<(u-1);
    }
    ti = cnt = 0; Fill(head,-1);
    for(int i=1;i<=n-1;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v,1);
        add(v,u,1);
    }
    dfs_id(1,-1);
    build(1,1,n);
    while(q--){
        int op; scanf("%d",&op);
        if(op == 1) {
            int u,v;
            scanf("%d%d",&u,&v);
            update(1,p1[u],p2[u],v);
        }
        else {
            int u; scanf("%d",&u);
            ll x = query(1,p1[u],p2[u]);
            int cnt = 0;
            while(x){
                if(x&1) cnt++;
                x >>= 1;
            }
            printf("%d\n",cnt);
        }
    }
}

你可能感兴趣的:(DFS序)