3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 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
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
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 ", tmp.mi); 220 } 221 } 222 return 0; 223 }