BZOJ3083: 遥远的国度

3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 1280 MB
Submit: 4198  Solved: 1109
[Submit][Status][Discuss]

Description

描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成 了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有 一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的 话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但 zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数 p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output


对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1

Sample Output

1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

HINT

Source

 

树剖序列其实就是一个dfs序,用树剖的方法查询/修改路径,dfs序的方法查询/修改子树

 

换根操作:手画一颗比较复杂的树,设原根节点为root,换根后为now,会发现只有查询root->now这条路径上的子树时,换根操作才会带来影响。

设查询子树的根节点为u,u在root->now的路径上,整棵树集合为G,以u在root->now的路径上的儿子为根的子树为G',查询范围其实是G - G',这样就把dfs序分成了2~3块,有一块不需要查,查剩余1~2块即可

 

dfs序处理子树区间l,r时,跟着树剖的第二遍dfs顺便做就好了

 

倍增手残写错卡了半天。。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #define min(a, b) ((a) < (b) ? (a) : (b))
  9 #define max(a, b) ((a) > (b) ? (a) : (b))
 10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 11 inline void swap(int &a, int &b)
 12 {
 13     int tmp = a;a = b;b = tmp;
 14 }
 15 inline void read(int &x)
 16 {
 17     x = 0;char ch = getchar(), c = ch;
 18     while(ch < '0' || ch > '9') c = ch, ch = getchar();
 19     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
 20     if(c == '-') x = -x;
 21 }
 22 
 23 const int INF = 0x3f3f3f3f;
 24 const int MAXN = 500000 + 10;
 25 
 26 struct Edge
 27 {
 28     int u,v,nxt;
 29     Edge(int _u, int _v, int _nxt){u = _u;v = _v;nxt = _nxt;}
 30     Edge(){} 
 31 }edge[MAXN << 1];
 32 int head[MAXN], cnt;
 33 inline void insert(int a, int b)
 34 {
 35     edge[++cnt] = Edge(a,b,head[a]);
 36     head[a] = cnt;
 37 }
 38 int root,now,top[MAXN],w[MAXN],fa[MAXN],rank[MAXN],tim,deep[MAXN],tid[MAXN],size[MAXN],son[MAXN],n,q,l[MAXN],r[MAXN],p[MAXN][30],M;
 39 
 40 void dfs1(int u)
 41 {
 42     size[u] = 1;
 43     for(register int pos = head[u];pos;pos = edge[pos].nxt)
 44     {
 45         int v = edge[pos].v;
 46         if(v == fa[u]) continue;
 47         fa[v] = u;p[v][0] = u;deep[v] = deep[u] + 1;dfs1(v);
 48         size[u] += size[v];
 49         if(son[u] == -1 || size[v] > size[son[u]]) son[u] = v;
 50     }
 51 }
 52 void dfs2(int u, int tp)
 53 {
 54     tid[u] = ++ tim, rank[tim] = u;top[u] = tp;l[u] = r[u] = tim;
 55     if(son[u] == -1) return;
 56     dfs2(son[u], tp);
 57     for(register int pos = head[u];pos;pos = edge[pos].nxt)
 58     {
 59         int v = edge[pos].v;
 60         if(v != fa[u] && v != son[u]) dfs2(v, v);
 61     }
 62     r[u] = tim;
 63 }
 64 struct Node
 65 {
 66     int l,r,mi,lazy;
 67     Node(){l = r = mi = lazy = 0;}
 68 }node[MAXN << 2];
 69 void pushup(Node &a, Node &l, Node &r)
 70 {
 71     if(a.lazy)
 72     {
 73         l.mi = r.mi = a.lazy;
 74         l.lazy = r.lazy = a.lazy;
 75         a.lazy = 0;
 76     }
 77 }
 78 Node merge(Node &a, Node &b)
 79 {
 80     if(a.l == 0) return b;
 81     if(b.l == 0) return a;
 82     Node re;re.l = a.l, re.r = b.r;
 83     re.mi = min(a.mi, b.mi);
 84     return re;
 85 }
 86 void build(int o = 1, int l = 1, int r = n)
 87 {
 88     node[o].l = l, node[o].r = r;
 89     if(l == r)
 90     {
 91         node[o].mi = w[rank[l]];
 92         return;
 93     }
 94     int mid = (node[o].l + node[o].r) >> 1;
 95     build(o << 1, l, mid);
 96     build(o << 1 | 1, mid + 1, r);
 97     node[o] = merge(node[o << 1], node[o << 1 | 1]);
 98     return;
 99 }
100 void modify(int ll, int rr, int k, int o = 1)
101 {
102     pushup(node[o], node[o << 1], node[o << 1 | 1]);
103     if(ll <= node[o].l && rr >= node[o].r)
104     {
105         node[o].mi = k;
106         node[o].lazy = k;
107         return;
108     }
109     int mid = (node[o].l + node[o].r) >> 1;
110     if(mid >= ll) modify(ll, rr, k, o << 1);
111     if(mid < rr) modify(ll, rr, k, o << 1 | 1);
112     node[o] = merge(node[o << 1], node[o << 1 | 1]);
113     return;
114 }
115 Node ask(int ll, int rr, int o = 1)
116 {
117     pushup(node[o], node[o << 1], node[o << 1 | 1]);
118     if(ll <= node[o].l && rr >= node[o].r) return node[o];
119     int mid = (node[o].l + node[o].r) >> 1;
120     Node a,b;
121     if(mid >= ll) a = ask(ll, rr, o << 1);
122     if(mid < rr) b = ask(ll, rr, o << 1 | 1);
123     if(a.l == 0) return b;
124     else if(b.l == 0) return a;
125     return merge(a, b);
126 }
127 
128 void yuchuli()
129 {
130     M = 0;
131     while((1 << M) <= n) ++ M;
132     -- M;
133     for(register int i = 1;i <= M;++ i)
134         for(register int j = 1;j <= n;++ j)
135             p[j][i] = p[p[j][i - 1]][i - 1];
136 } 
137 
138 int LCA(int u, int v)
139 {
140     if(deep[u] < deep[v]) swap(u, v);
141     for(register int i = M;i >= 0;-- i)
142         if(deep[u] - (1 << i) >= deep[v])
143             u = p[u][i];
144     if(u == v) return u;
145     for(register int i = M;i >= 0;-- i)
146         if(p[u][i] != p[v][i])
147             u = p[u][i], v = p[v][i];
148     return fa[u];
149 }
150 
151 //找根为now的情况下x子树最小 
152 Node find(int x)
153 {
154     Node re;
155     if(now == root)
156         re = ask(l[x], r[x]);
157     else
158     {
159         int lca = LCA(x, now);
160         if(lca != x) re = ask(l[x], r[x]);
161         else
162         {
163             int tmp = now;
164             for(register int i = M;i >= 0;-- i)
165                 if(deep[p[tmp][i]] > deep[x])
166                     tmp = p[tmp][i];
167             Node tmp1,tmp2;    
168             if(l[tmp] - 1 >= 1)    tmp1 = ask(1, l[tmp] - 1);
169             if(r[tmp] + 1 <= n) tmp2 = ask(r[tmp] + 1, n);
170             re = merge(tmp1, tmp2);
171         }
172     }
173     return re;
174 }
175 
176 //修改路径 
177 void change(int x, int y, int k)
178 {
179     int f1 = top[x], f2 = top[y];
180     while(f1 != f2)
181     {
182         if(deep[f1] < deep[f2]) swap(f1, f2), swap(x, y);
183         modify(tid[f1], tid[x], k);
184         x = fa[f1], f1 = top[x];
185     }
186     if(deep[x] > deep[y]) swap(x, y);
187     modify(tid[x], tid[y], k);
188 }
189 
190 int main()
191 {
192     memset(son, -1, sizeof(son));
193     read(n), read(q);
194     for(register int i = 1;i < n;++ i)
195     {
196         int tmp1,tmp2;read(tmp1), read(tmp2);
197         insert(tmp1, tmp2), insert(tmp2, tmp1);
198     }
199     for(register int i = 1;i <= n;++ i) read(w[i]);
200     read(root);now = root;
201     dfs1(root);
202     dfs2(root, root);
203     build();
204     yuchuli();
205     for(register int i = 1;i <= q;++ i)
206     {
207         int opt;read(opt);
208         if(opt == 1) read(now);
209         else if(opt == 2)
210         {
211             int tmp1, tmp2, tmp3;
212             read(tmp1), read(tmp2), read(tmp3);
213             change(tmp1, tmp2, tmp3);
214         }
215         else
216         {
217             read(opt);
218             Node tmp = find(opt);
219             printf("%d\n", tmp.mi);
220         }
221     }
222     return 0;
223 }
BZOJ3083

 

posted @ 2018-01-17 23:38  嘒彼小星  阅读(190)  评论(2编辑  收藏  举报