Codeforces 620E New Year Tree dfs + 线段树(区间查询+区间置数) + 位运算
2016-01-30 14:41
519 查看
题意
给你一棵树n(4e5)个节点,每个节点有一种颜色(60种以下的颜色)有两种操作,修改一棵子树所有节点的颜色为c
查询,一颗子树下有多少种颜色
思路
先考虑,如果是在一个数组里,每次修改一个区间和查询一个区间怎么做?基本想法,就是线段树记录下每个区间内的颜色都有哪些,然后就可以归并了
由于只有60种颜色,我们可以用位压缩编码,然后归并的时候,就是按位取或即可
所以,这棵线段树维护的就是一个取或的运算
由于有区间置数,需要标志下移啥的就不多说了~
然后我们的问题,就是把一棵子树的节点映射到一段连续的区间上
我们通过后序周游的方法就可以做到,对于节点u的子树,我们记录它最左的叶子节点对应的数组位置pos_l,后它自己的所在的数组位置pos_r,[pos_l, pos_r]既是我们所要更新或查询的区间
实现
#include <bits/stdc++.h> using namespace std; const int maxn = 4e5 + 5; typedef long long ll; typedef pair<int,int> pii; #define pb push_back #define mp make_pair #define fi first #define se second ll setv[maxn<<2]; ll orv[maxn<<2]; vector<ll> a; pii id[maxn]; ll col[maxn]; vector<int> g[maxn]; int n,m; ll build(int u, int l, int r){ if (l == r){ return orv[u] = a[l]; } int mid = (l+r)/2, chl = 2 * u + 1, chr = 2 * u + 2; return orv[u] = build(chl, l, mid) | build(chr, mid+1, r); } int x1,x2; ll c; void update(int u, int l, int r){ if (x1 <= l && x2 >= r){ orv[u] = c; setv[u] = c; return; } if (x1 > r || x2 < l){ return; } int mid = (l+r)/2, chl = 2 * u + 1, chr = 2 * u + 2; //标志下移 if (setv[u] != 0){ orv[chl] = orv[chr] = setv[chl] = setv[chr] = setv[u]; setv[u] = 0; } update(chl, l, mid); update(chr, mid+1, r); orv[u] = orv[chr] | orv[chl]; } ll query(int u,int l, int r){ if (x1 > r || x2 < l){ return 0; } if (setv[u] != 0){ return setv[u]; } if (x1 <= l && x2 >= r){ return orv[u]; } int mid = (l+r)/2, chl = 2 * u + 1, chr = 2 * u + 2; return query(chl, l, mid) | query(chr, mid+1, r); } int mark[maxn]; int dfs(int u){ mark[u] = 1; int tmp = -1; for (int e=0; e<g[u].size();e++){ int v = g[u][e]; if (mark[v] == 1){ continue; } if (tmp == -1){ tmp = dfs(v); } else{ dfs(v); } } if (tmp == -1){ tmp = a.size(); } id[u] = mp(tmp, a.size()); a.pb(col[u]); return tmp; } int main(){ ios::sync_with_stdio(false); cin>>n>>m; for (int i=1;i<=n;i++){ int c; cin>>c; col[i] = (ll)1 << (ll)(c-1); } for (int i=0;i<n-1;i++){ int u,v; cin>>u>>v; g[u].pb(v); g[v].pb(u); } dfs(1); //for (int i=1;i<=n;i++){ // cout << id[i].fi << "," << id[i].se << endl; //} build(0, 0, a.size()-1); for (int i=0;i<m;i++){ int t,x,y; cin>>t; if (t == 1){ cin>>x>>y; x1 = id[x].fi; x2 = id[x].se; c = (ll)1 << (ll)(y-1); update(0, 0, a.size()-1); } else{ cin>>x; x1 = id[x].fi; x2 = id[x].se; ll tmp = query(0, 0, a.size()-1); int ans = 0; while (tmp > 0){ if (tmp & 1LL){ ans++; } tmp >>= 1LL; } cout << ans << endl; } } return 0; }
相关文章推荐
- 一个5年运维工程师的新年回首
- 缓存、缓存算法和缓存框架
- 数据绑定框架:Databinding
- UVA 514
- Python 面向对象编程(一)
- 设计模式——简单工厂模式
- Servlet服务器 HTTP 响应
- android学习记录2(日志、上下文、android下数据存储、xml基础)
- 如何使用angularjs实现文本框设置值
- U8采购订单联查采购入库单
- 神经网络 --学习之路,资料汇编
- pycharm 注册码
- 数据结构与算法的联系
- CSAPP Lab5--Writing a Dynamic Storage Allocator
- jquery 动态添加表格行
- Java字节序
- 【leetcode】Valid Parentheses(easy)
- 写日志的那些事儿
- JQUEry查找父元素和子元素
- hdu 1063 Exponentiation 大数