题目

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. Gradle常用功能拾掇

    介绍 Gradle 是一个基于groovy动态语言的java项目管理工具,灵活性和速度好于java,他的build脚本完全可以以写groovy代码的方式来实现,所以灵活性很高,当然也就比maven的x ...

  2. 【Azure Developer】如何通过Azure Portal快速获取到对应操作的API并转换为Python代码

    问题描述 对于Azure资源进行配置操作,门户上可以正常操作.但是想通过Python代码实现,这样可以批量处理.那么在没有SDK的情况下,是否有快速办法呢? 问题解答 当然可以,Azure Porta ...

  3. k8s错误集合

    1.etcd没有启动的 [root@mcwk8s03 ~]# kubectl get nodesUnable to connect to the server: context deadline ex ...

  4. Django项目windows上开发,虚拟机上调通打包,生产环境解压即用

    linux上部署Django项目 首先创建一个简易的Django项目 使用自动生成的这个数据库 压缩上传 解压运行,不可以 [root@mcw1 /opt/mcwtest]$ ls app01 db. ...

  5. Avalonia中的线性渐变画刷LinearGradientBrush

    在WPF中使用Shape实现复杂线条动画后,尝试在Avalonia中也实现同样效果.尽管官方提供了从WPF到Avalonia的快速入门文档,但由于第一次使用Avalonia,体验过程中并不是很顺利,主 ...

  6. 【题解】A18537.我心中珍藏的游戏

    题目跳转 思路: 题目问最多可以获得的额外伤害,其实就是询问在这些技能中,如何怎样选取一个最优的发动技能顺序使得攻击加成最大.我们可以把每一个技能看作成一个图的顶点,把每一个攻击加成看作图的边,权制为 ...

  7. c# 记一次批量获取自己的qq好友的CF游戏战绩

    突然想耍穿越火线,就下载了,想看看自己的战绩就在这个网址上查:https://cf.qq.com/wx/zjcx.htm,后来又想看看qq好友的战绩,就得一个一个得复制粘贴qq,选择大区.我这时候就像 ...

  8. PaddleOCR之高性能Go语言实现OCR识别

    最近为了让python语言能够直接调用PaddleOCR的C++的动态链接库,针对本人已经开源的PaddleOCR项目https://gitee.com/raoyutian/paddle-ocrsha ...

  9. Nodejs静态资源管理 路由

    express提供了一个非常好用的方法,叫做 express.static(),通过此方法,可以非常方便地创建一个静态web资源服务器 app.use(express.static('public') ...

  10. .net6 .net core web api json 遇到 400 错误

    环境: .net6 webapi 服务端模型声明 public class TongYiMinPgPayReq { public string mch_no { get; set; } public ...