您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: