标签:
题目链接:http://codeforces.com/problemset/problem/722/C
题意:
有 n 个正整数序列。同时 n 个摧毁序列,从 1 到 n每次把正整数序列里对应下标的数字去掉,成为一个间隔。
问每去掉一个数字,序列中最大的连续子段和。
思路:
倒着想,这道题就变成了:从 n 到 1每次出现一个数字,若数字的两边已经存在集合,则把存在的集合合并为一个,
并更新集合的和,否则单独为一个集合。过程中始终维护序列中目前所有集合里和的最大值。
代码:
#include <iostream> #include <stdio.h> #include <cstring> #include <map> #include <queue> #include <set> #include <cmath> #include <time.h> #include <cstdlib> #include <algorithm> #define lson (i<<1) #define rson (lson|1) using namespace std; typedef long long LL; const int N = 100007; const int INF = 0x7fffffff; int pre[N], isR[N], n, num[N], pos[N], cnt_ans; LL val[N], ans[N], maxN; int find(int x) { if (pre[x] == x) return x; else return pre[x] = find(pre[x]); } void merge(int x, int y) { int fx = find(x); int fy = find(y); if (fx != fy) { pre[fx] = fy; isR[fx] = 0; val[fy] += val[fx]; if (val[fy] > maxN) maxN = val[fy]; } } int main() { while (scanf("%d", &n) != EOF) { ans[0] = 0; cnt_ans = 1; for (int i = 1; i <= n; i++) { scanf("%d", &num[i]); pre[i] = i; isR[i] = 0; val[i] = (LL)num[i]; } for (int i = 1; i <= n; i++) scanf("%d", &pos[i]); maxN = -1; for (int i = n; i > 0; i--) { isR[pos[i]] = 1; if (val[pos[i]] > maxN) maxN = val[pos[i]]; if (pos[i] + 1 <= n && isR[find(pos[i]+1)]) merge(pos[i], pos[i] + 1); if (pos[i] - 1 > 0 && isR[find(pos[i]-1)]) merge(pos[i] - 1, pos[i]); ans[cnt_ans++] = maxN; } for (int i = cnt_ans - 2; i >= 0; i--) printf("%lld\n", ans[i]); } }
Codeforces 722C Destroying Array(并查集)*
标签:
原文地址:http://www.cnblogs.com/burning-flame/p/5930825.html