bzoj 2243 树链剖分+线段树

bzoj 2243 树链剖分+线段树

题目描述

   在一颗点数为N<100,000的树上,每个点有一个颜色。请你实现两种操作 1. 给一段路径u->v染色 2. 询问路径u->v上有多少种颜色

吐槽:

    1. 4KB的代码...
    2. 唉.... 这题的思路非常好想... 但是我还是捉了好久....真弱...
    3. 我尽量把代码写的清楚了...

算法分析:

    1. 基于树的动态统计,还是要先做树链剖分
    2. 至于线段怎么维护是个问题,这里我的方法是: 线段树记录每个区间的颜色段数,和最左段与最右段的颜色。更新的话要用到懒惰标记法。
    3. 比维护/查询边要好写吧....

  1
  //  figo 5.16.2012
  2  //  template & head file
  3 #include<cassert>
  4 #include<iostream>
  5 #include<cstdio>
  6 #include<cstring>
  7  using  namespace std;
  8 template <typename T> inline  void chkmin(T &a, const T b) {  if(a > b) a = b;}
  9 template <typename T> inline  void chkmax(T &a, const T b) {  if(a < b) a = b;}
 10  //  graph
 11  const  int V = 100005;
 12  const  int E = V * 2;
 13  int head[V],pnt[E],nxt[E],color[V],e,n;
 14  void add_edge( int u, int v){
 15     nxt[e] = head[u];
 16     head[u] = e;
 17     pnt[e] = v;
 18     e ++;
 19 }
 20  //  segment tree
 21  int LT,RT;
 22  int lt[V<<2], rt[V<<2] ,clr[V<<2], cover[V<<2];
 23  void pushdown( int pos, int L, int R){
 24      if(L == R){  return;}
 25      if(cover[pos] == 1) {
 26         cover[pos]= 0;
 27         clr[pos<<1] = clr[pos<<1|1] = 1;
 28         lt[pos<<1] = rt[pos<<1] = lt[pos<<1|1] = rt[pos<<1|1] = lt[pos];
 29         cover[pos<<1] = cover[pos<<1|1] = 1;
 30     }
 31 }
 32  void upt( int pos, int L, int R){
 33      if(L==R)  return;
 34     lt[pos] = lt[pos << 1];
 35     rt[pos] = rt[pos << 1 | 1];
 36     clr[pos] = clr[pos<<1] + clr[pos<<1|1] - (rt[pos<<1]==lt[pos<<1|1]);
 37 }
 38  int __ans,__last;
 39  void update( int l, int r, int pos, int L, int R, char cmd, int c = 0){
 40      if(L >= l && R <= r){
 41          if(cmd == 'C'){
 42             cover[pos] = clr[pos] = 1;
 43             lt[pos] = rt[pos] = c;
 44         }
 45          if(L == l) LT = lt[pos];
 46          if(R == r) RT = rt[pos];
 47         __ans += clr[pos] - (__last==lt[pos]);
 48         __last = rt[pos];
 49          return;
 50     }
 51     pushdown(pos,L,R);
 52      int mid = L + R >> 1;
 53      if(mid >= l) update(l,r,pos << 1, L, mid,cmd, c);
 54      if(mid < r) update(l,r,pos<<1|1, mid+1,R,cmd, c);
 55     upt(pos,L,R);
 56 }
 57  //  dsu
 58  int parent[V];
 59  int find( int u){
 60      return u == parent[u] ? u : parent[u] = find(parent[u]);
 61 }
 62  //  divide and conquer
 63  const  int inf = ~0u>>2;
 64  int sz[V],P[V],heavy[V],deep[V],flag[V];
 65  int dfs( int u, int f){
 66      int mx = -1, s = -1;
 67     sz[u] = 1;
 68      for( int i = head[u];i!=-1; i = nxt[i]){
 69          int v = pnt[i];
 70          if(v == f)  continue;
 71         deep[v] = deep[u] + 1;
 72         P[v] = u;
 73         dfs(v,u);
 74         sz[u] += sz[v];
 75          if(sz[v] > mx){
 76             mx = sz[v]; s = v;
 77         }
 78     }
 79     heavy[u] = s;
 80      if(s >= 0) parent[s] = u;
 81 }
 82  int prepare(){
 83      for( int i =0; i<n; i++) parent[i] = i;
 84     deep[0] = 0;P[0] = -1;
 85     dfs(0,0);
 86      int segsz = 0;
 87      for( int i=0; i<n; i++)  if(heavy[i] == -1){
 88          int v = i;
 89          while(v && heavy[P[v]] == v){
 90             update(segsz,segsz,1,0,n,'C',color[v]);
 91             flag[v] = segsz ++;
 92             v = P[v];
 93         }
 94         update(segsz,segsz,1,0,n,'C',color[v]);
 95         flag[v] = segsz ++;
 96     }
 97     assert(segsz==n);
 98 }
 99  //  operator
100  int lca( int u, int v){
101      while(1){
102          int U = find(u);
103          int V = find(v);
104          if(U == V)  return deep[u] < deep[v] ? u : v;
105          else  if(deep[U] >= deep[V])
106             u = P[U];
107          else v = P[V];
108     }
109 }
110  int query( int u, int p, char cmd, int c=0){
111      int ans = 0;
112      int last = -1;
113      while(u != P[p]){
114          int l = flag[u];
115          int v = find(u);
116          if(deep[v]<deep[p]) v = p;
117          int r = flag[v];
118         __ans =0; __last = -1;
119         update(l,r,1,0,n,cmd,c);
120         ans += __ans - (LT == last);
121         last = RT;
122         u = P[v];
123     }
124      return ans;
125 }
126  //  main
127  int ask( int u, int v, char cmd, int c=0){
128      int p = lca(u,v);
129      return query(u,p,cmd,c) + query(v,p,cmd,c) - 1;
130 }
131  int main(){
132      int m,u,v;
133     scanf("%d%d",&n,&m);
134     e = 0;
135      for( int i=0;i<n;i++) head[i] = -1;
136      for( int i=0;i<n;i++) scanf("%d",&color[i]);
137      for( int i=1;i<n;i++){
138         scanf("%d%d",&u,&v);
139         u--; v--;
140         add_edge(u,v);
141         add_edge(v,u);
142     }
143     prepare();
144      char cmd[2]; int c=0;
145      while(m--){
146         scanf("%s%d%d",cmd,&u,&v);
147         u--; v--;
148          if(cmd[0]=='C') scanf("%d",&c);
149          int ans = ask(u,v,cmd[0],c);
150          if(cmd[0]=='Q') printf("%d\n",ans);
151     }
152 }

你可能感兴趣的:(bzoj 2243 树链剖分+线段树)