Codeforces 620E New Year Tree(线段树)

题目链接 New Year Tree

考虑到ck <= 60,那么用位运算统计颜色种数

对于每个点,重新标号并算出他对应的进和出的时间,然后区间更新+查询。

用线段树来维护。

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4
  5 #define rep(i, a, b) for (int i(a); i <= (b); ++i)
  6
  7 struct node{
  8     long long num, lazy;
  9 } tree[400010 << 2];
 10
 11 struct Node{
 12     int l, r;
 13 } e[400010];
 14
 15 vector <int> v[400010];
 16
 17 int n, m;
 18 long long val[400010], c[400010];
 19 int Time;
 20 bool vis[400010];
 21 long long ans, cover;
 22 int op;
 23 int x, y;
 24
 25 void dfs(int x, int fa){
 26     e[x].l = ++Time;
 27     val[Time] = c[x];
 28     vis[x] = true;
 29     for (auto u : v[x]){
 30         if (u == fa) continue;
 31         dfs(u, x);
 32     }
 33
 34     e[x].r = Time;
 35 }
 36
 37 inline void pushup(int i){
 38     tree[i].num = tree[i << 1].num | tree[i << 1 | 1].num;
 39 }
 40
 41 inline void pushdown(int i){
 42     if (tree[i].lazy){
 43         tree[i << 1].num = tree[i << 1 | 1].num = (1LL << tree[i].lazy);
 44         tree[i << 1].lazy = tree[i << 1 | 1].lazy = tree[i].lazy;
 45         tree[i].lazy = 0;
 46     }
 47 }
 48
 49 void build(int i, int l, int r){
 50     tree[i].lazy = 0;
 51     if (l == r){
 52         tree[i].num = (1LL << val[l]);
 53         return ;
 54     }
 55
 56     int mid = (l + r) >> 1;
 57     build(i << 1, l, mid);
 58     build(i << 1 | 1, mid + 1, r);
 59     pushup(i);
 60 }
 61
 62 void update(int i, int L, int R, int l, int r, long long cover){
 63     if (l <= L && R <= r){
 64         tree[i].lazy = cover;
 65         tree[i].num = (1LL << cover);
 66         return ;
 67     }
 68
 69     int mid = (L + R) >> 1;
 70     pushdown(i);
 71     if (l <= mid) update(i << 1, L, mid, l, r, cover);
 72     if (r > mid) update(i << 1 | 1, mid + 1, R, l, r, cover);
 73     pushup(i);
 74 }
 75
 76 void solve(int i, int L, int R, int l, int r){
 77     if (l <= L && R <= r){
 78         ans |= tree[i].num;
 79         return;
 80     }
 81
 82     pushdown(i);
 83     int mid = (L + R) >> 1;
 84     if (l <= mid) solve(i << 1, L, mid, l, r);
 85     if (r > mid) solve(i << 1 | 1, mid + 1, R, l, r);
 86 }
 87
 88 int main(){
 89
 90     scanf("%d%d", &n, &m);
 91
 92     rep(i, 1, n) v[i].clear();
 93     rep(i, 1, n) scanf("%lld", c + i);
 94     rep(i, 1, n - 1){
 95         scanf("%d%d", &x, &y);
 96         v[x].push_back(y);
 97         v[y].push_back(x);
 98     }
 99
100     memset(vis, 0, sizeof vis); Time = 0;
101     dfs(1, 0);
102     build(1, 1, n);
103
104     rep(i, 1, m){
105         scanf("%d%d", &op, &x);
106         if (op == 1){
107             scanf("%lld", &cover);
108             update(1, 1, n, e[x].l, e[x].r, cover);
109         }
110
111         else{
112             ans = 0;
113             solve(1, 1, n, e[x].l, e[x].r);
114             int ret = 0;
115             for (; ans; ans -= ans & -ans) ++ret;
116             printf("%d\n", ret);
117         }
118     }
119
120     return 0;
121 }
时间: 2024-10-22 17:14:59

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

CodeForces 620E New Year Tree(线段树的骚操作第二弹)

The New Year holidays are over, but Resha doesn't want to throw away the New Year tree. He invited his best friends Kerim and Gural to help him to redecorate the New Year tree. The New Year tree is an undirected tree with n vertices and root in the v

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

HDU 4107 Gangster Segment Tree线段树

这道题也有点新意,就是需要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提高速度的目的. 本题过的人很少,因为大部分都超时了,我严格按照线段树的方法去写,一开始居然也超时. 然后修补了两个地方就过了,具体修改的地方请参看程序. 知道最大值段和最小值段,然后修补一下就能过了.不是特别难的题目. #include <stdio.h> #include <string> #include <algorithm> using namespace std; c

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

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in

codeforces 482B. Interesting Array【线段树区间更新】

题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val.就是区间l---r上的与的值为val,最后问你原来的数组是多少?如果不存在输出no 分析:分析发现要满足所有的区间,而一个点上假如有多个区间的话,这个点的值就是所有区间或的值,因为只有这样才能满足所有区间的,把所有位上的1都保存下来了,那么可以发现用线段树来维护,但是那么怎么判断满不满足条件呢?可以也用线段树,更新了之后在整个维护一遍看看满不满足题意,如

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing

CodeForces 600E Lomsat gelral(线段树合并)

题目链接:http://codeforces.com/problemset/problem/600/E You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the