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

 

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\n",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

 

posted @ 2019-10-30 17:49  HHHyacinth  阅读(162)  评论(0编辑  收藏  举报