Codeforces 620E New Year Tree(DFS序+线段树)

题目大概说给一棵树,树上结点都有颜色(1到60),进行下面两个操作:把某结点为根的子树染成某一颜色、询问某结点为根的子树有多少种颜色。

子树,显然DFS序,把子树结点映射到连续的区间。而注意到颜色60种,这样就可以用一个64位整型去表示颜色的集合,然后就是在这个连续区间中用线段树成段更新颜色集合和区间查询颜色集合了。

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 #define MAXN 500000
  5 struct Edge{
  6     int v,next;
  7 }edge[MAXN<<1];
  8 int NE,head[MAXN];
  9 void addEdge(int u,int v){
 10     edge[NE].v=v; edge[NE].next=head[u];
 11     head[u]=NE++;
 12 }
 13
 14 int l[MAXN],r[MAXN],dfn;
 15 void dfs(int u,int fa){
 16     l[u]=++dfn;
 17     for(int i=head[u]; i!=-1; i=edge[i].next){
 18         int v=edge[i].v;
 19         if(v==fa) continue;
 20         dfs(v,u);
 21     }
 22     r[u]=dfn;
 23 }
 24
 25 long long tree[MAXN<<2],lazy[MAXN<<2],z;
 26 int N,x,y;
 27 void update(int i,int j,int k){
 28     if(x<=i && j<=y){
 29         tree[k]=z;
 30         lazy[k]=z;
 31         return;
 32     }
 33     if(lazy[k]){
 34         tree[k<<1]=lazy[k];
 35         tree[k<<1|1]=lazy[k];
 36         lazy[k<<1]=lazy[k];
 37         lazy[k<<1|1]=lazy[k];
 38         lazy[k]=0;
 39     }
 40     int mid=i+j>>1;
 41     if(x<=mid) update(i,mid,k<<1);
 42     if(y>mid) update(mid+1,j,k<<1|1);
 43     tree[k]=tree[k<<1]|tree[k<<1|1];
 44 }
 45 long long query(int i,int j,int k){
 46     if(x<=i && j<=y){
 47         return tree[k];
 48     }
 49     if(lazy[k]){
 50         tree[k<<1]=lazy[k];
 51         tree[k<<1|1]=lazy[k];
 52         lazy[k<<1]=lazy[k];
 53         lazy[k<<1|1]=lazy[k];
 54         lazy[k]=0;
 55     }
 56     int mid=i+j>>1;
 57     long long res=0;
 58     if(x<=mid) res|=query(i,mid,k<<1);
 59     if(y>mid) res|=query(mid+1,j,k<<1|1);
 60     return res;
 61 }
 62
 63 int getCount(long long s){
 64     int cnt=0;
 65     for(int i=0; i<60; ++i){
 66         if(s>>i&1) ++cnt;
 67     }
 68     return cnt;
 69 }
 70
 71 int color[MAXN];
 72 int main(){
 73     int n,m;
 74     scanf("%d%d",&n,&m);
 75     for(int i=1; i<=n; ++i){
 76         scanf("%d",color+i);
 77         --color[i];
 78     }
 79     memset(head,-1,sizeof(head));
 80     int a,b,c;
 81     for(int i=1; i<n; ++i){
 82         scanf("%d%d",&a,&b);
 83         addEdge(a,b);
 84         addEdge(b,a);
 85     }
 86     dfs(1,1);
 87     for(N=1; N<n; N<<=1);
 88     for(int i=1; i<=n; ++i){
 89         x=l[i]; y=l[i]; z=1LL<<color[i];
 90         update(1,N,1);
 91     }
 92     while(m--){
 93         scanf("%d",&c);
 94         if(c==1){
 95             scanf("%d%d",&a,&b);
 96             x=l[a]; y=r[a]; z=1LL<<b-1;
 97             update(1,N,1);
 98         }else{
 99             scanf("%d",&a);
100             x=l[a]; y=r[a];
101             printf("%d\n",getCount(query(1,N,1)));
102         }
103     }
104     return 0;
105 }
时间: 2024-08-09 10:36:43

Codeforces 620E New Year Tree(DFS序+线段树)的相关文章

codeforces 617E. New Year Tree dfs序+线段树+bitset

题目链接 给一棵树, 每个节点有颜色, 两种操作, 一种是将一个节点的子树全都染色成c, 一种是查询一个节点的子树有多少个不同的颜色, c<=60. 每个节点一个bitset维护就可以. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include

POJ3321 - Apple Tree DFS序 + 线段树或树状数组

Apple Tree:http://poj.org/problem?id=3321 题意: 告诉你一棵树,每棵树开始每个点上都有一个苹果,有两种操作,一种是计算以x为根的树上有几个苹果,一种是转换x这个点上的苹果,就是有就去掉,没有就加上. 思路: 先对树求一遍dfs序,每个点保存一个l,r.l是最早到这个点的时间戳,r是这个点子树中的最大时间戳,这样就转化为区间问题,可以用树状数组,或线段树维护区间的和. #include <algorithm> #include <iterator&

codechef T6 Pishty and tree dfs序+线段树

PSHTTR: Pishty 和城堡题目描述 Pishty 是生活在胡斯特市的一个小男孩.胡斯特是胡克兰境内的一个古城,以其中世纪风格 的古堡和非常聪明的熊闻名全国. 胡斯特的镇城之宝是就是这么一座古堡,历史上胡斯特依靠这座古堡抵挡住了疯人国的大军. 对于 Pishty 来说,真正吸引他的是古堡悠长的走廊和高耸的钟楼,以及深藏于其中的秘密-- 古堡可以用一棵 N 个节点的树的描述,树中有 N ?1 条无向边,每条边有一个魔法数字 C. 当一个旅游团参观古堡时,他们会选择树上 U 到 V 的路径游

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

Educational Codeforces Round 6 E dfs序+线段树

题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili上电子科技大学发的视频学习的 将一颗树通过dfs编号的方式 使每个点的子树的编号连在一起作为相连的区间 就可以配合线段树搞子树 因为以前好像听说过 线段树可以解决一种区间修改和查询区间中不同的xx个数...所以一下子就想到了... 但是我不会写线段树..只会最简单的单点修改区间查询...不会用延迟标

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

POJ 3321 DFS序+线段树

单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include <cstdio> 6: #include <cstring> 7: #include <cctype> 8: #include <algorithm> 9: #include <vector> 10: #include <iostream> 1

codevs1228 (dfs序+线段树)

总结: 第一次遇到dfs序的问题,对于一颗树,记录节点 i 开始搜索的序号 Left[i] 和结束搜索的序号 Righti[i],那么序号在 Left[i] ~ Right[i] 之间的都是节点 i 子树上的节点. 并且此序号与线段树中 L~R 区间对应,在纸上模拟了几遍确实如此,但暂时还未理解为何对应. 此题就是dfs序+线段树的裸题 代码: #include<iostream> #include<vector> #include<cstring> #include&

[BZOJ 3306]树(dfs序+线段树+倍增)

Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Solution 单点修改子树查询的话可以想到用dfs序+线段树来处理,换根的处理画一画图应该可以明白: 如果查询的x是当前的根rt,直接返回整棵树的min 如果rt在x的子树中,用倍增的方法找到离x最近的rt的祖先t,整棵树除t的子树以外的部分就是x当前根下的子树 如果rt不在x的子树中,查询x原来的子树的min值 #include<iostream> #include<

【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\),问你答案是多少. \(n\leq {10}^5,k\leq {10}^9\) 题解 设\(l\)为这棵树的叶子个数,显然当\(k>\)树的深度时答案都是\(l\). 下面要证明:答案是\(O(l+\frac{n-l}{k})\)的. 我们从下往上贪心,每次选择一个未被覆盖的深度最深的点,覆盖这个点网