• CodeForces 620E"New Year Tree"(DFS序+线段树+状态压缩)


    传送门

    •题意

      给你一颗 n 个节点的树,每个节点被染上了颜色;

      有 m 次操作,每次操作的类型有两种

      • 1 v c : 将以 v 为根的子树的结点全部涂成 c
      • 2 v : 询问以 v 为根的子树的结点中不同颜色的数量

    •题解

      因为操作的是某个节点对应的子树,所以我们可以通过DFS序获得每一个结点的子树区间。

      之后我们就将这个树形的问题转化成了一个线性区间的问题;

      然后,就可以用线段树来维护(区间更新,区间查询);

      求解某个区间不同颜色的个数要怎么办呢?

      刚开始,我在线段树中定义了一个 $set$,存储当前区间所有的颜色;

      但是,用 $set$ 超时了;

      因为总共的颜色最多只有 60 种;

      因此我们可以用一个范围在 $long long$ 内的二进制数 $bit$ 存储每一种颜色;

      ($bit$ 的二进制下的每一位代表着一种颜色)

    •Code

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define ll long long
      4 #define ls(x) (x<<1)
      5 #define rs(x) (x<<1|1)
      6 #define mem(a,b) memset(a,b,sizeof(a))
      7 #define popcount(x) __builtin_popcountll(x)///获取x的二进制位1的个数
      8 const int maxn=4e5+50;
      9 
     10 int n,m;
     11 int a[maxn];
     12 int num;
     13 int head[maxn];
     14 struct Edge
     15 {
     16     int to;
     17     int next;
     18 }G[maxn<<1];
     19 void addEdge(int u,int v)
     20 {
     21     G[num]={v,head[u]};
     22     head[u]=num++;
     23 }
     24 struct Seg
     25 {
     26     int l,r;
     27     ll sum;
     28     int lazy;
     29     int mid(){return l+((r-l)>>1);};
     30     void Set(int col)
     31     {
     32         sum=1ll<<col;
     33         lazy=col;
     34     }
     35 }seg[maxn<<2];
     36 
     37 ///[s[u],e[u]]区间表示以u为根节点的子树的所有节点所在的区间
     38 int s[maxn];
     39 int e[maxn];
     40 vector<int >vs;
     41 void DFS(int u,int f)
     42 {
     43     vs.push_back(u);
     44     s[u]=vs.size()-1;
     45     for(int i=head[u];~i;i=G[i].next)
     46     {
     47         int v=G[i].to;
     48         if(v != f)
     49             DFS(v,u);
     50     }
     51     e[u]=vs.size()-1;
     52 }
     53 void pushUp(int pos)
     54 {
     55     seg[pos].sum=seg[ls(pos)].sum|seg[rs(pos)].sum;
     56 }
     57 void pushDown(int pos)
     58 {
     59     int &lazy=seg[pos].lazy;
     60     if(lazy == -1)
     61         return ;
     62 
     63     seg[ls(pos)].Set(lazy);
     64     seg[rs(pos)].Set(lazy);
     65 
     66     lazy=-1;
     67 }
     68 void build(int l,int r,int pos)
     69 {
     70     seg[pos]={l,r};
     71     seg[pos].lazy=-1;
     72 
     73     if(l == r)
     74     {
     75         seg[pos].sum=1ll<<a[vs[l]];
     76         return ;
     77     }
     78 
     79     int mid=seg[pos].mid();
     80     build(l,mid,ls(pos));
     81     build(mid+1,r,rs(pos));
     82 
     83     pushUp(pos);
     84 }
     85 void update(int pos,int l,int r,int col)
     86 {
     87     if(seg[pos].l == l && seg[pos].r == r)
     88     {
     89         seg[pos].Set(col);
     90         return ;
     91     }
     92     pushDown(pos);
     93 
     94     int mid=seg[pos].mid();
     95     if(r <= mid)
     96         update(ls(pos),l,r,col);
     97     else if(l > mid)
     98         update(rs(pos),l,r,col);
     99     else
    100     {
    101         update(ls(pos),l,mid,col);
    102         update(rs(pos),mid+1,r,col);
    103     }
    104     pushUp(pos);
    105 }
    106 ll query(int pos,int l,int r)
    107 {
    108     if(seg[pos].l == l && seg[pos].r == r)
    109         return seg[pos].sum;
    110     pushDown(pos);
    111 
    112     int mid=seg[pos].mid();
    113     if(r <= mid)
    114         return query(ls(pos),l,r);
    115     else if(l > mid)
    116         return query(rs(pos),l,r);
    117     else
    118         return query(ls(pos),l,mid)|query(rs(pos),mid+1,r);
    119 }
    120 void Solve()
    121 {
    122     vs.clear();
    123     DFS(1,1);
    124     build(0,vs.size()-1,1);
    125 
    126     while(m--)
    127     {
    128         int op;
    129         scanf("%d",&op);
    130         if(op == 1)
    131         {
    132             int v,c;
    133             scanf("%d%d",&v,&c);
    134             update(1,s[v],e[v],c);///更新v节点对应的子树节点区间[s[v],e[v]]的颜色
    135         }
    136         else
    137         {
    138             int v;
    139             scanf("%d",&v);
    140             ll ans=query(1,s[v],e[v]);
    141             printf("%d
    ",popcount(ans));
    142         }
    143     }
    144 }
    145 void Init()
    146 {
    147     num=0;
    148     mem(head,-1);
    149 }
    150 int main()
    151 {
    152 //    freopen("C:\Users\hyacinthLJP\Desktop\C++WorkSpace\in&&out\contest","r",stdin);
    153     Init();
    154     scanf("%d%d",&n,&m);
    155     for(int i=1;i <= n;++i)
    156         scanf("%d",a+i);
    157     for(int i=1;i < n;++i)
    158     {
    159         int u,v;
    160         scanf("%d%d",&u,&v);
    161         addEdge(u,v);
    162         addEdge(v,u);
    163     }
    164     Solve();
    165 
    166     return 0;
    167 }
    View Code
  • 相关阅读:
    JVM 启动参数设置
    Linux文件分割与合并
    设置tomcat使用指定的jdk版本
    java字符编码
    HASH 哈希处理完数据导致数据集第一行数据缺失
    HASH 何时将key加载到h.definedata()中
    字符串 批量全角、半角转换
    SAS_正则表达式 字符意义
    正则表达式基础篇
    sas options有用的全局设置
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11766465.html
Copyright © 2020-2023  润新知