CodeForces - 620E New Year Tree

New Year Tree

 CodeForces - 620E 

给出一棵树,每个结点刚开始的时候都有一个颜色,现在有查询
1 u col:给这个结点及其子树染上col这种颜色
2 u:查询以u为根节点的子树的所有颜色种类

/*
    维护子树信息,应该想到求出dfs序,在序列上维护,用线段树或者树状数组什么的搞一搞
    对于这个题: 
    遍历树一边,得出dfs序 
    建一棵线段树,每个节点维护一个long long 的val值(val分为60位分别状压60种颜色)表示当前区间是否存在某种颜色
    然后标记下传同理,然后就是线段树区间修改区间查询了
    非常要注意的是1<<i会爆,一定要写1LL<<i 
*/
#include<iostream>
#include<cstdio>
#define maxn 400010
using namespace std;
int xu[maxn],num,head[maxn],n,p,sz[maxn],opl,opr,opv,mp[maxn],color[maxn];
struct node{int to,pre;}e[maxn*2];
struct Node{int l,r;long long col,lazy;}tr[maxn*16];
void Insert(int from,int to){
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
void build(int l,int r,int k){
    tr[k].l=l;tr[k].r=r;
    if(l==r){
        int x;
        tr[k].col=(1<<color[mp[l]]-1);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tr[k].col=tr[k<<1].col|tr[k<<1|1].col;
}
int id;
void dfs(int now,int father){
    xu[now]=++id;mp[id]=now;
    sz[now]=1;
    for(int i=head[now];i;i=e[i].pre){
        int to=e[i].to;
        if(to==father)continue;
        dfs(to,now);
        sz[now]+=sz[to];
    }
}
int count(long long x){
    int res=0;
    while(x){
        res++;
        x-=(x&-x);
    }
    return res;
}
void update(int k){
    tr[k<<1].lazy=tr[k].lazy;
    tr[k<<1].col=tr[k].lazy;
    tr[k<<1|1].lazy=tr[k].lazy;
    tr[k<<1|1].col=tr[k].lazy;
    tr[k].lazy=0;
}
void change(int l,int r,int k){
    if(l>=opl&&r<=opr){
        tr[k].col=1<<opv-1;
        tr[k].lazy=1<<opv-1;
        return;
    }
    if(tr[k].lazy)update(k);
    int mid=(l+r)>>1;
    if(opl<=mid)change(l,mid,k<<1);
    if(opr>mid)change(mid+1,r,k<<1|1);
    tr[k].col=tr[k<<1].col|tr[k<<1|1].col;
}
long long query(int l,int r,int k){
    if(l>=opl&&r<=opr)return tr[k].col;
    if(tr[k].lazy)update(k);
    int mid=(l+r)>>1;
    long long res=0;
    if(opl<=mid)res|=query(l,mid,k<<1);
    if(opr>mid)res|=query(mid+1,r,k<<1|1);
    tr[k].col=tr[k<<1].col|tr[k<<1|1].col;
    return res;
}
int co(long long x){
    for(int i=1;i<=6;i++){
        if(x&(1<<i))return i;
    }
}
int main(){
    freopen("Cola.txt","r",stdin);
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)scanf("%d",&color[i]);
    int op,x,y;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        Insert(x,y);Insert(y,x);
    }
    dfs(1,0);build(1,n,1);
    for(int i=1;i<=p;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&x,&opv);
            opl=xu[x],opr=xu[x]+sz[x]-1;
            change(1,n,1);
        }
        if(op==2){
            scanf("%d",&x);
            opl=xu[x],opr=xu[x]+sz[x]-1;
            long long w=query(1,n,1);
            printf("%d\n",count(w));
        }
    }
}

 

转载于:https://www.cnblogs.com/thmyl/p/7738922.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值