CF620E

题目

CF620E

思路

这个题是一个在树上操作的题,每次操作的对象都是以一个结点为根的子树,在1e5的操作下暴力做法必然会超时
观察到c的范围很小,可以考虑状态压缩
考虑将此问题转化为区间问题,利用线段树求解
可以观察到一个结点为根的子树对应的区间是它所对应的dfs序区间
以题目中所给的这棵树为例
img
整棵树的dfs序为1 4 3 6 5 7 2
如果我们要将根为3的子树涂成2这个颜色,3对应的dfs序为3 6 5 7,对应的区间为 \([3,6]\)
所以我们只要对该区间操作即可
\(sum[nod]\) 表示为nod的结点所包含的颜色,用二进制表示
原来的上浮操作就是 \(sum[nod] = sum[ls(nod)] | sum[rs(nod)]\)
最后求答案的时候我们只需要在1~60位上找到1有多少个即可

代码

非复制版

img

可复制版

#include<iostream>
#include<utility>
#include<vector>
using namespace std;
typedef long long ll;
#define endl '\n'
#define fi(a,b) for(int i = a; i <= b; ++i)
#define fr(a,b) for(int i = a; i >= b; --i)
using pii = pair<int,int>;
const int N = 4e5+5;
#define int long long
int Tree[4 * N];
int sum[4 * N];
int n,m;
int tag[4 * N];
int son[N];
int head[N];
int cnt = 1;
int num;
int df[N];
int inde[N];
//#define DEBUG
struct edge{
    int b,w,ne;
}edge[2*N];
void add(int a,int b,int c){
    edge[cnt].b = b;
    edge[cnt].w = c;
    edge[cnt].ne = head[a];
    head[a] = cnt++;
}
int dfs(int x,int fa){
    for(int i = head[x]; i != 0; i = edge[i].ne){
        if(edge[i].b == fa) continue;
        else {
            df[++num] = edge[i].b;
            inde[edge[i].b] = num;
            son[x] += dfs(edge[i].b,x);
        }
    }
    son[x] = son[x] + 1;
    return son[x];

}
inline int ls(int nod){
    return nod << 1;
}
inline int rs(int nod){
    return (nod << 1) | 1;
}
inline void build(int l,int r,int nod){
    if(l == r)
        {
            int x = df[l];

            sum[nod] = (long long)1 << Tree[df[l]];
            return;
        }
    int mid = l + (r - l >> 1);
    build(l,mid,2 * nod);
    build(mid+1,r,2 * nod + 1);
    sum[nod] = sum[2 * nod] | sum[2 * nod + 1];
}
inline void pushdown(int l, int r,int nod){
    int mid = l + (r - l >> 1);
    tag[ls(nod)] = tag[nod];
    tag[rs(nod)] = tag[nod];
    sum[ls(nod)] = tag[nod];
    sum[rs(nod)] = tag[nod]; 
    tag[nod] = 0;
}
inline void updata(int x,int y, int l,int r,int nod,int data){
    if(l >= x && r <= y) 
    {
        sum[nod] = (long long)1 << data;
        tag[nod] = sum[nod];  
        return;      
    }
    if(tag[nod]) pushdown(l,r,nod);
    int mid = l + (r - l >> 1);
    if(x <= mid) updata(x,y,l,mid,ls(nod),data);
    if(y > mid) updata(x,y,mid + 1,r,rs(nod),data);
    sum[nod] = sum[ls(nod)] | sum[rs(nod)];
}
inline int summ(int x,int y,int l,int r, int nod){
    if(l >= x && r <= y){
        return sum[nod];
    }
    if(tag[nod]) pushdown(l,r,nod);
    int mid = l + (r - l >> 1);
    int s = 0;
    if(x <= mid)
    s |= summ(x,y,l,mid,ls(nod));
    if(y > mid)
    s |= summ(x,y,mid + 1,r,rs(nod));
    return s;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    fi(1,n) cin >> Tree[i];
    for(int i = 1; i < n; i++){
        int a,b;
        cin >> a >> b;
        add(a,b,1);
        add(b,a,1);
    }
    df[++num] = 1;
    inde[1] = num;
    dfs(1,0);
    build(1,n,1);
    for(int i = 1; i <= m; i++)
    {
        int op;
        cin >> op;
        if(op == 1){
            int u,c;
            cin >> u >> c;
            updata(inde[u],inde[u]+son[u]-1,1,n,1,c);
        }
        else{
            int u;
            cin >> u;
            int res = 0;
            int p = summ(inde[u],inde[u]+son[u]-1,1,n,1);
            for(int i = 1; i <= 60; i++) {
                if(p >> i & 1){
                    res++;
                }
            }
            cout << res << endl;
        }
    }
    return 0;
}
posted @ 2022-09-02 18:27  Sun-Wind  阅读(23)  评论(0编辑  收藏  举报