bzoj 4336[BJOI2015]骑士的旅行 - 树链剖分 + mulitiset

4336: BJOI2015 骑士的旅行

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

在一片古老的土地上,有一个繁荣的文明。
这片大地几乎被森林覆盖,有N座城坐落其中。巧合的是,这N座城由恰好N-1条双向道路连接起来,使得任意两座城都是连通的。
也就是说,这些城形成了树的结构,任意两座城之间有且仅有一条简单路径。
在这个文明中,骑士是尤其受到尊崇的职业。任何一名骑士,都是其家族乃至家乡的荣耀。Henry从小就渴望成为一名能守护家乡、驱逐敌人的骑士。勤奋训练许多年后,Henry终于满18岁了。他决定离开家乡,向那些成名已久的骑士们发起挑战!根据Henry的调查,大陆上一共有M名受封骑士,不妨编号为1到M。
第i个骑士居住在城Pi,武力值为Fi。Henry计划进行若干次旅行,每次从某座城出发沿着唯一的简单路径前往另一座城,
同时会挑战路线上武力值最高的K个骑士(Henry的体力有限,为了提高水平,当然要挑战最强的骑士)。如果路线上的骑士不足K人,Henry会挑战遇到的所有人。
每次旅行前,可能会有某些骑士的武力值或定居地发生变化,Henry自然会打听消息,并对计划做出调整。
为了在每次旅行时做好充分准备,Henry希望你能帮忙在每次旅行前计算出这条路线上他将挑战哪些对手。
 

Input

第一行,一个整数N,表示有N座城,编号为1~N。
接下来N-1行,每行两个整数Ui和Vi,表示城Ui和城Vi之间有一条道路相连。
第N+1行,一个整数M,表示有M个骑士。
接下来M行,每行两个整数Fi和Pi。按顺序依次表示编号为1~M的每名骑士的武
力值和居住地。
第N+M+2行,两个整数Q,K,分别表示操作次数和每次旅行挑战的骑士数目上限。
接下来Q行,每行三个整数Ti,Xi,Yi。Ti取值范围为{1,2,3},表示操作类型。
一共有以下三种类型的操作:
Ti=1时表示一次旅行,Henry将从城Xi出发前往城市Yi;
Ti=2时表示编号为Xi的骑士的居住地搬到城Yi;
Ti=3时表示编号为Xi的骑士的武力值修正为Yi。

Output

输出若干行,依次为每个旅行的答案。
对每个Ti=1的询问,输出一行,按从大到小的顺序输出Henry在这次旅行中挑战的
所有骑士的武力值。如果路线上没有骑士,输出一行,为一个整数-1。

Sample Input

5
1 2
1 3
2 4
2 5
4
10 1
6 1
14 5
7 3
5 3
1 2 3
1 5 3
1 4 4
2 1 4
1 2 3

Sample Output

10 7 6
14 10 7
-1
7 6

HINT

 

100%的数据中,1 ≤ N, M ≤ 40,000,1 ≤ Ui, Vi, Pi ≤ N,1 ≤ Q ≤ 80,000, 1 ≤ K ≤ 

20,旅行次数不超过 40,000 次,武力值为不超过1,000的正整数。 
 
 
对于这类树上问题,可以考虑树链剖分解决
重点是如何维护前k大个
对于一个单点,可以用muiliset 直接按顺序存储所有的人
这样向上合并的时候就用归并的思想很简单就解决了。
 
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <set>
  6 #define LL long long
  7 
  8 using namespace std;
  9 
 10 const int MAXN = 5e4 + 10;
 11 
 12 int T;
 13 int x, y;
 14 multiset<int> city[MAXN];
 15 int ans[30];
 16 int N, M;
 17 int head[MAXN];
 18 int m[MAXN];
 19 int cnt = 0;
 20 int vis[MAXN];
 21 int dfn[MAXN], top[MAXN], fa[MAXN];
 22 int size[MAXN], son[MAXN];
 23 int deep[MAXN];
 24 int Q, K;
 25 
 26 struct edge {
 27     int v;
 28     int next;
 29 } g[MAXN * 2];
 30 
 31 struct segment {
 32     int l, r;
 33     int big[30];
 34 } seg[MAXN * 20];
 35 
 36 struct knight {
 37     int force, loc;
 38 } kt[MAXN];
 39 
 40 void addedge(int u, int v)
 41 {
 42     g[++cnt].v = v;
 43     g[cnt].next = head[u];
 44     head[u] = cnt;
 45 }
 46 
 47 inline LL read()
 48 {
 49     LL x = 0, w = 1; char ch = 0;
 50     while(ch < '0' || ch > '9') {
 51         if(ch == '-') {
 52             w = -1;
 53         }
 54         ch = getchar();
 55     }
 56     while(ch >= '0' && ch <= '9') {
 57         x = x * 10 + ch - '0';
 58         ch = getchar();
 59     }
 60     return x * w;
 61 }
 62 
 63 void pushup(int x)
 64 {
 65     int l1 = 1, l2 = 1;
 66     for(int i = 1; i <= K; i++) {
 67         if(seg[x * 2].big[l1] >= seg[x * 2 + 1].big[l2]) {
 68             seg[x].big[i] = seg[x * 2].big[l1++];
 69         } else {
 70             seg[x].big[i] = seg[x * 2 + 1].big[l2++];
 71         }
 72     }
 73 }
 74 
 75 void merge(int x)
 76 {
 77     int temp[30];
 78     int l1 = 1, l2 = 1;
 79     for(int i = 1; i <= K; i++) {
 80         temp[i] = ans[i];
 81     }
 82     for(int i = 1; i <= K; i++) {
 83         if(temp[l1] >= seg[x].big[l2]) {
 84             ans[i] = temp[l1++];
 85         } else {
 86             ans[i] = seg[x].big[l2++];
 87         }
 88     }
 89 }
 90 
 91 void dfs1(int x)
 92 {
 93     deep[x] = deep[fa[x]] + 1;
 94     size[x] = 1;
 95     vis[x] = 1;
 96     for(int j = head[x]; j; j = g[j].next) {
 97         int to = g[j].v;
 98         if(!vis[to]) {
 99             fa[to] = x;
100             dfs1(to);
101             size[x] += size[to];
102             if(size[to] > size[son[x]]) {
103                 son[x] = to;
104             }
105         }
106     }
107 }
108 
109 void dfs2(int x, int k)
110 {
111     top[x] = k;
112     dfn[x] = ++cnt;
113     m[cnt] = x;
114     if(son[x]) {
115         dfs2(son[x], k);
116     }
117     for(int j = head[x]; j; j = g[j].next) {
118         int to = g[j].v;
119         if(!dfn[to]) {
120             dfs2(to, to);
121         }
122     }
123 }
124 
125 void update(int u, int l, int r, int root, int k)
126 {
127     if(l == r) {
128         city[m[l]].insert(k);
129         multiset<int>::iterator t;
130         int i = 1;
131         t = city[m[l]].end();
132         t--;
133         for(; i <= K; i++, t--) {
134             seg[root].big[i] = *t;
135             if(t == city[m[l]].begin()) {
136                 i++;
137                 for(; i <= K; i++) {
138                     seg[root].big[i] = 0;
139                 }
140                 break;
141             }
142         }
143         return;
144     }
145     int mid = (l + r) >> 1;
146     if(u <= mid) {
147         update(u, l, mid, root * 2, k);
148     } else {
149         update(u, mid + 1, r, root * 2 + 1, k);
150     }
151     pushup(root);
152 }
153 
154 void del(int u, int l, int r, int root, int k)
155 {
156     if(l == r) {
157         multiset<int> :: iterator t;
158         t = city[m[l]].find(k);
159         city[m[l]].erase(t);
160         int i = 1;
161         t = city[m[l]].end();
162         if(city[m[l]].empty()) {
163             for(int i = 1; i <= K; i++) {
164                 seg[root].big[i] = 0;
165             }
166             return;
167         }
168         t--;
169         for(; i <= K; i++, t--) {
170             seg[root].big[i] = *t;
171             if(t == city[m[l]].begin()) {
172                 i++;
173                 for(;i <= K; i++) {
174                     seg[root].big[i] = 0;
175                 }
176                 break;
177             }
178         }
179         return;
180     }
181     int mid = (l + r) >> 1;
182     if(u <= mid) {
183         del(u, l, mid, root * 2, k);
184     } else {
185         del(u, mid + 1, r, root * 2 + 1, k);
186     }
187     pushup(root);
188 }
189 
190 void build()
191 {
192     dfs1(1);
193     cnt = 0;
194     dfs2(1, 1);
195 }
196 
197 void query(int ql, int qr, int l, int r, int root)
198 {
199     if(l >= ql && r <= qr) {
200         merge(root);
201         return;
202     }
203     int mid = (l + r) >> 1;
204     if(mid >= ql) {
205         query(ql, qr, l, mid, root * 2);
206     }
207     if(mid < qr) {
208         query(ql, qr, mid + 1, r, root * 2 + 1);
209     }
210 }
211 
212 int LCA(int x, int y)
213 {
214     int fx = top[x], fy = top[y];
215     while(fx != fy) {
216         if(deep[fx] >= deep[fy]) {
217             query(dfn[fx], dfn[x], 1, N, 1);
218             x = fa[fx];
219             fx = top[x];
220         } else {
221             query(dfn[fy], dfn[y], 1, N, 1);
222             y = fa[fy];
223             fy = top[y];
224         }
225     }
226     if(deep[x] >= deep[y]) {
227         query(dfn[y], dfn[x], 1, N, 1);
228         return y;
229     } else {
230         query(dfn[x], dfn[y], 1, N, 1);
231         return x;
232     }
233 }
234 
235 int main()
236 { 
237     //freopen("knight10.in", "r", stdin);
238     //freopen("knight.out", "w", stdout);
239     N = read();
240     for(int i = 1; i < N; i++) {
241         int u = read(), v = read();
242         addedge(u, v);
243         addedge(v, u);
244     }
245     build();
246     M = read();
247     for(int i = 1; i <= M; i++) {
248         kt[i].force = read(), kt[i].loc = read();
249     } 
250     Q = read(), K = read();
251     for(int i = 1; i <= M; i++) {
252         update(dfn[kt[i].loc], 1, N, 1, kt[i].force);
253     }
254     int tot = 1;
255     while(Q--) {
256         /*cout<<tot++<<endl;
257         multiset<int> ::iterator t;
258         t = city[4527].begin();
259         for(; t != city[4527].end(); t++) {
260             cout<<*t<<" ";
261         }
262         cout<<endl;*/ 
263         T = read();
264         x = read(), y = read();
265         //cout<<T<<" "<<x<<" "<<y<<endl; 
266         if(T == 1) {
267             for(int i = 1; i <= K; i++) {
268                 ans[i] = 0;
269             }
270             /*if(x == 1 && y == 2){
271                 multiset<int> ::iterator t;
272                 t = city[x].begin();
273                 for(; t != city[x].end(); t++) {
274                     cout<<*t<<" ";
275                 }
276                 cout<<endl;
277                 
278             }*/
279             LCA(x, y);
280             /*for(int i = 1; i <= N; i++) {
281                 for(int j = 1; j <= 20; j++) {
282                     ans[j] = 0;
283                 }
284                 query(dfn[i], dfn[i], 1, N, 1);
285                 for(int j = 1; j <= 3; j++) {
286                     cout<<ans[j]<<" ";
287                 }
288                 cout<<endl<<endl;
289             }*/
290             for(int i = 1; i <= K; i++) {
291                 if(ans[i] == 0) {
292                     if(i == 1) {
293                         printf("-1");
294                     }
295                     break;
296                 }
297                 printf("%d ", ans[i]);
298             }
299             printf("\n");
300         } else if(T == 2) {
301             /*if(x == 720 && y == 6713) {
302                 cout<<dfn[kt[x].loc] <<" "<<kt[x].force<<" "<<kt[x].loc<<endl;
303                 multiset<int> ::iterator t;
304                 t = city[kt[x].loc].begin();
305                 for(; t != city[kt[x].loc].end(); t++) {
306                     cout<<*t<<" ";
307                 }
308                 cout<<endl;
309                 return 0;
310             }*/
311             del(dfn[kt[x].loc], 1, N, 1, kt[x].force);
312             kt[x].loc = y;
313             update(dfn[kt[x].loc], 1, N, 1, kt[x].force);
314         } else {
315             del(dfn[kt[x].loc], 1, N, 1, kt[x].force);
316             kt[x].force = y;
317             update(dfn[kt[x].loc], 1, N, 1, kt[x].force);
318         }
319     }
320 }    
321 
322 
323 /*
324 5 
325 
326 1 2 
327 
328 1 3 
329 
330 2 4 
331 
332 2 5 
333 
334 4 
335 
336 10 1 
337 
338 6 1 
339 
340 14 5 
341 
342 7 3 
343 
344 5 3 
345 
346 1 2 3 
347 
348 1 5 3 
349 
350 1 4 4 
351 
352 2 1 4 
353 
354 1 2 3 
355 
356 */
View Code

 

 

转载于:https://www.cnblogs.com/wuenze/p/8570576.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值