codeforces 620 E 线段树压位加建树

该博客介绍了codeforces 620 E题的解决方案,涉及利用线段树和DFS序在树上处理祖先和子孙颜色更新及查询的问题。作者提到了一个常见的错误,即在处理颜色数量时忘记考虑超过60种颜色的情况,导致WA(Wrong Answer),并提醒读者注意此类细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

codeforces 620 E cf620E

题意 一颗树 更新祖先 和其子孙的颜色 , 询问祖先里面有多少个颜色

统计区间颜色我们容易算 问题就是如何化成区间 利用dfs序 找到出现的顺序 建树

然后按照统计颜色的做法做久好了 我一开始WA是因为60个颜色1<<60忘记加 ll 所以wa了 这也是这类题目的一个wa点 需要注意

/*
codeforces 620E
*/
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <sstream>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 800024;
int n;
long long s[MAX_N<<2],col[MAX_N<<2];
int fa[MAX_N],a[MAX_N],p[MAX_N],low[MAX_N],high[MAX_N],vis[MAX_N],val[MAX_N],eid,dep;
struct edge {
    int v,next;
}e[MAX_N<<1];
void init(){
    memset(p,-1,sizeof(p));
    memset(vis,0,sizeof(vis));
    memset(col,-1,sizeof(col));
    eid = 0;
    dep = 0;
}
void Insert(int u,int v){
    e[eid].v = v ;
    e[eid].next = p[u];
    p[u] = eid++;
}

void up(int rt){
    s[rt] = s[rt<<1] | s[rt<<1|1];
}
void down(int rt,int l,int r){
    if(col[rt]!=-1){
        col[rt<<1] = col[rt<<1|1] = col[rt];
        s[rt<<1] = s[rt<<1|1] = (1ll<<(col[rt]-1));
        //dbg(s[rt<<1]);
        //dbg(s[rt<<1|1]);
        col[rt] = -1;
    }
}
void modify(int rt,int l,int r,int x,int y,int v){
    if(x<=l&&r<=y){
        col[rt] = v;
        s[rt] = (1ll<<(v-1));
        //dbg(s[rt]);
        return ;
    }
    int mid = (l+r)>>1;
    down(rt,l,r);
    if(x<=mid) modify(rt<<1,l,mid,x,y,v);
    if(mid<y) modify(rt<<1|1,mid+1,r,x,y,v);
    up(rt);
}
long long query(int rt,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        return s[rt];
    }
    int mid = (l+r)>>1;
    down(rt,l,r);
    long long ret1 = 0,ret2 = 0,ret3;
    if(x<=mid) ret1 = query(rt<<1,l,mid,x,y);
    if(mid<y) ret2 = query(rt<<1|1,mid+1,r,x,y);
    ret3 = ret1 | ret2;
    return ret3;
}
void dfs(int u){
    low[u]=++dep;
    vis[u] = 1;
    val[dep] = a[u];
    for(int i = p[u];i!=-1;i=e[i].next){
        if(!vis[e[i].v]) dfs(e[i].v);
    }
    high[u] = dep;
}
void build(int rt,int l,int r){
    if(l==r){
    s[rt] = (1ll<<(val[l]-1));
    col[rt] = -1;
    return ;
    }
    int mid = (l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    up(rt);

}
int main(){
    int m;
    scanf("%d%d",&n,&m);
    init();
    for(int i = 1;i<=n;++i)
        scanf("%d",&a[i]);
    for(int i = 1;i<n;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        Insert(x,y);
        Insert(y,x);
    }
    dfs(1);
    build(1,1,n);
    int opt,x,y;
    while(m--){
    scanf("%d",&opt);
    if(opt==1){
    scanf("%d%d",&x,&y);
    modify(1,1,n,low[x],high[x],y);
    }
    else {
    scanf("%d",&x);
    long long ans = query(1,1,n,low[x],high[x]);
    int cnt= 0;
    for(;ans;ans-=ans&(-ans)) cnt++;
    printf("%d\n",cnt);
    }

    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值