首页 > 代码库 > Codeforces 722C Destroying Array(并查集)*

Codeforces 722C Destroying Array(并查集)*

题目链接: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(并查集)*