Codeforces 620E New Year Tree dfs + 线段树(区间查询+区间置数) + 位运算

来源:互联网 发布:西安交大网络公开课 编辑:程序博客网 时间:2024/06/02 05:14

题意

  • 给你一棵树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 secondll 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;}
1 0
原创粉丝点击