题目

CF620E

思路

这个题是一个在树上操作的题,每次操作的对象都是以一个结点为根的子树,在1e5的操作下暴力做法必然会超时

观察到c的范围很小,可以考虑状态压缩

考虑将此问题转化为区间问题,利用线段树求解

可以观察到一个结点为根的子树对应的区间是它所对应的dfs序区间

以题目中所给的这棵树为例



整棵树的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有多少个即可

代码

非复制版

可复制版

#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;
}

CF620E的更多相关文章

  1. CF620E New Year Tree 线段树 dfs序

    luogu链接 题目大意: 有一个节点有颜色的树 操作1.修改子树的颜色 操作2.查询子树颜色的种类 注意,颜色种类小于60种 只有子树的操作,dfs序当然是最好的选择 dfs序列是什么,懒得讲了,自 ...

  2. [CF620E]New Year Tree

    题目大意:有一棵以$1$为根的有根树,有$n$个点,每个节点初始有颜色$c_i$.有两种操作: $1 v c:$将以$v$为根的子树中所有点颜色更改为$c$ $2 v:$ 查询以$v$为根的子树中的节 ...

  3. 线段树+Dfs序【CF620E】New Year Tree

    Description 你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]. 有两种操作: 1 v c 将以v为根的子树中所有点颜色更改为c 2 v 查询以v为根的子树中的节点有多少种 ...

  4. 线段树【CF620E】The Child and Sequence

    Description At the children's day, the child came to Picks's house, and messed his house up. Picks w ...

  5. CF620E New Year Tree 状压+线段树(+dfs序?)

    借用学长的活:60种颜色是突破口(我咋不知道QAQ) 好像这几道都是线段树+dfs序??于是你可以把60种颜色压进一个long long 里,然后向上合并的时候与一下(太妙了~) 所以记得开long ...

  6. CF620E New Year Tree(线段树+二进制)

    题解 弱智题,二进制表示位数.合并时用| 就是被1<<x卡了好久. 要写成1ll<<x才行 #include<iostream> #include<cstri ...

  7. CF620E New Year Tree 线段树+dfs序+bitset

    线段树维护 dfs 序是显然的. 暴力建 60 个线段树太慢,于是用 bitset 优化就好了 ~ code: #include <bits/stdc++.h> #define M 63 ...

  8. [CF620E]New Year Tree_dfs序_线段树_bitset

    New Year Tree 题目链接:http://codeforces.com/problemset/problem/620/E 数据范围:略. 题解: 转化成序列问题,发现颜色种数特别少,暴力用数 ...

  9. 【CF620E】New Year Tree

    (题面来自luogu) 题意翻译 你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]. 有两种操作: 1 v c 将以v为根的子树中所有点颜色更改为c 2 v 查询以v为根的子树中的节 ...

  10. 题解 CF620E 【New Year Tree】

    有关dfs序的例题,需要有一定的位运算基础 题面 给定一个树,树上有颜色,将某一子树的颜色统一修改,求子树中颜色的数量 Solution 子树修改,子树求和,dfs序的知识(类似区间修改区间求和) 考 ...

随机推荐

  1. 密码学—RSA公钥算法Python程序

    RSA流程 选取两个素数p,q,保密p,q 计算出n = p×q ,公开n 计算φ(n)=(p-1)(q-1) ,保密φ(n) 选择一个数e ,e满足:e < φ(n) , gcd(e,φ(n) ...

  2. DashVector x 通义千问大模型:打造基于专属知识的问答服务

    本教程演示如何使用向量检索服务(DashVector),结合LLM大模型等能力,来打造基于垂直领域专属知识等问答服务.其中LLM大模型能力,以及文本向量生成等能力,这里基于灵积模型服务上的通义千问 A ...

  3. Vue——安装

    Vue.js 设计的初衷就包括可以被渐进式地采用.这意味着它可以根据需求以多种方式集成到一个项目中. 将 Vue.js 添加到项目中主要有四种方式: 1.在页面上以 CDN 包的形式导入. <s ...

  4. SSH-Web 工具之 shellinabox:一款使用 AJAX 的基于 Web 的终端模拟器 安装及使用教程

    本文转载自: shellinabox:一款使用 AJAX 的基于 Web 的终端模拟器 一.shellinabox简介 通常情况下,我们在访问任何远程服务器时,会使用常见的通信工具如OpenSSH和P ...

  5. kubernetes configmap配置方法

    configmap解释 在k8s运行期间会有一些依赖的配置文件,他们存在宿主机中的一个目录中或者代码里,如果配置放生变化,pod在另一台服务器启动,在没有这些配置的时候,可能会导致pod无法正常运行, ...

  6. 8.10考试总结(NOIP模拟35)[玩游戏·排列·最短路·矩形]

    所谓人,无论是谁到了最后,都会形单影只. T1 玩游戏 解题思路 可以把序列从 k 位置掰成两个序列. 问题就变成了两个序列从开头走向末尾是否可以保证前缀和之和一直不大于 0 . 并且可以移动到两个序 ...

  7. uniapp 输入有值后按钮变色

    我们在开发中难免会遇到一些登录注册输入框中的值为空时,按钮的状态变成为不可点击的状态,当输入框有值后就把按钮变为可点击的状态 代码部分: <input placeholder="请输入 ...

  8. k8s集群创建阿里云版本

    阿里云创建k8s集群实例 创建两个8G内存的抢占实例(青岛),能ssh 默认关闭防火墙,且没有交换分区 配置/etc/hosts,主机名 配置k8s仓库 配置命令补全 安装docker(需要conta ...

  9. c# IdHelper生成唯一的雪花Id

    为什么使用雪花ID 在以前的项目中,最常见的两种主键类型是自增Id和UUID,在比较这两种ID之前首先要搞明白一个问题,就是为什么主键有序比无序查询效率要快,因为自增Id和UUID之间最大的不同点就在 ...

  10. kettle从入门到精通 第三十三课 再谈 kettle 表输出 分区/分片

    1.之前第九章有讲过kettle 表输出步骤,里面有简单的提到过表输出步骤里面的表分区设置,这里详细介绍下. 表分区数据:选择此选项可根据"分区"字段中指定的日期字段的值将数据拆分 ...