题目

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. mysql如何优雅的备份数据

    MySQL 有多种备份方式,以下是几种常用的备份方式: 使用 mysqldump 命令备份数据 mysqldump 是 MySQL 自带的备份工具,可以备份指定数据库或表的数据为 SQL 文件.可以通 ...

  2. 前端 PM 分享:PM 需要做的事情

    个人经验分享 PM PM( Project Manager ) PM( Product Manager ) 一.什么情况下需要前端担任 PM? 在我之前遇到的项目中,大多数项目的 PM 是由后端/产品 ...

  3. uniapp 图片懒加载的一种方式

    如果是列表页,可以采用前端分页,通过scroll-view 下拉,在绑定图片地址信息,这样就能下拉部分,加载部分图片了. pageQuery() { let currentPage = this.pQ ...

  4. SuperSocket AppServer.NewRequestReceived 不触发 接受不到字节

    SuperSocket AppServer.NewRequestReceived 不触发 接受不到字节 针对.netframework版本 1.6.* 使用 FixedHeaderReceiveFil ...

  5. Django——Media配置

    settings.py中的配置: MEDIA_ROOT 和 MEDIA_URL MEDIA_ROOT 是指:用户上传文件的根路径 --> MEDIA_ROOT = os.path.join(BA ...

  6. 深入探讨Function Calling:实现外部函数调用的工作原理

    引言 Function Calling 是一个允许大型语言模型(如 GPT)在生成文本的过程中调用外部函数或服务的功能. Function Calling允许我们以 JSON 格式向 LLM 模型描述 ...

  7. 13个优秀的AI工具软件导航网站推荐

    人工智能(AI)是现在科技领域的热门话题,它不仅改变了我们的生活方式,也催生了许多创新的工具和应用.AI工具可以帮助我们完成各种任务,如绘画.编程.视频制作.语音合成等,让我们的工作和娱乐更加高效和有 ...

  8. 『手撕Vue-CLI』拉取版本号

    开篇 在上一篇文章中,给 nue-cli 添加了与用户终端交互的功能,这一次来实现一个拉取版本号的功能. 这个功能的背景是,有时候我们在使用脚手架的时候,不同版本的脚手架可能会有不同的功能,所以用户有 ...

  9. C#.Net筑基-深入解密小数内部存储的秘密

    为什么0.1 + 0.2 不等于 0.3?为什么16777216f 等于 16777217f?为什么金钱计算都推荐用decimal?本文主要学习了解一下数字背后不为人知的存储秘密. 01.数值类型 C ...

  10. GeoGebra作圆的切线

    参考文档:<GeoGebra入门教程>唐家军 1. 目的 使用GeoGebra作出过一点的圆的切线. 2. 构造过程 文档种的描述如下: 按照上述构造过程,在输入条形框中依次输入上面的指令 ...