New Year Tree 【DFS序+线段树区间查询修改+二进制保存状态】

题目链接【http://codeforces.com/problemset/problem/620/E】

题意:给出n个数,每个数有一个初始的颜色。由这n个数组成一颗树。有两种操作1、将以节点u为根的子树的颜色染成k色。2、输出以节点u为根的子树的颜色总数。颜色有60种。

题解:1、用DFS重新对这棵树编号in[u],out[u]表示以节点u为根的子树的区间左右端点。2、用线段树维护更新与查询。3、颜色保存:se每一个二进制位表示一种颜色。0表示没有这种颜色,反之有。

因为有60种颜色,要用LL保存颜色。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6+5;
vector<int> v[maxn];
int in[maxn],out[maxn];
LL c[maxn];
int n,m;
int id;
void DFS_ORDER(int u)
{
    in[u] = ++id;
    for(int i = 0;i < v[u].size();i++)
    {
        int w = v[u][i];
        if(!in[w])    DFS_ORDER(w);
    }
    out[u] = id;
}
LL E[maxn*4],T[maxn*4];//值数组,标记数组
void update(int id,int l,int r,int In,int Out,LL val)
{
    if(r < In || l > Out)//不重合
        return ;
    if(l >= In && Out >= r)//包含
    {
        E[id] = val;
        T[id] = val;
        return ;
    }
    if(T[id])//相交
    {
        int mid = (l+r)>>1;
        T[id << 1] = T[id];
        E[id << 1] = T[id];
        T[id << 1 | 1] = T[id];
        E[id << 1 | 1] = T[id];
        T[id] = 0;//取消标记
    }
    int mid = (l+r) >>1;
    update(id<<1,l,mid,In,Out,val);
    update(id<<1|1,mid+1,r,In,Out,val);
    E[id] = E[id<<1]|E[id<<1|1];
}
LL query(int id,int l,int r,int In,int Out)
{
    if(r < In || l > Out)//不重合
        return 0;
    if(l >= In && Out >= r)//包含
        return E[id];
    if(T[id])//相交
    {
        int mid = (l+r)>>1;
        T[id << 1] = T[id];
        E[id << 1] = T[id];
        T[id << 1 | 1] = T[id];
        E[id << 1 | 1] = T[id];
        T[id] = 0;//取消标记
    }
    int mid = (l+r) >>1;
    LL ans1 = query(id<<1,l,mid,In,Out);
    LL ans2 = query(id<<1|1,mid+1,r,In,Out);
    return ans1|ans2;
}
int main ()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
        scanf("%lld", &c[i]);
    for(int i = 1;i <= n-1;i++)
    {
        int u,w;
        scanf("%d%d",&u,&w);
        v[u].push_back( w );
        v[w].push_back( u );
    }
    DFS_ORDER(1);
    for(int i = 1;i <= n;i++)
    {
        LL x = LL(1)<<(c[i]-1);
        update(1,1,n,in[i],in[i],x);
    }
    int ty,u;LL val;
    for(int i = 1;i <= m;i++)
    {
        scanf("%d",&ty);
        if(ty == 1)
        {
            scanf("%d%lld",&u,&val);
            LL x = LL(1)<<(val-1);
            update(1,1,n,in[u],out[u],x);
        }
        else
        {
            scanf("%d",&u);
            LL t = query(1,1,n,in[u],out[u]);
            int ans=0;
            while(t){if(t&1)ans++;t>>=1;}
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

posted @ 2016-12-30 11:14  _Mickey  阅读(309)  评论(0编辑  收藏  举报