并查集:CDOJ1593-老司机破阵 (假的并查集拆除)

老司机破阵

Time Limit: 4500/1500MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)

Problem Description

老司机的女朋友被坏人抓起来了,护女票心切的老司机心急火燎的赶到坏人藏匿女票的地点想要救出她,但是老司机的神通广大坏人们早有耳闻,等老司机赶到时已经有一个法阵摆在他的面前阻挡着他。
法阵是一条直线上的n个法力元件构成的,老司机每次可以将一个法力元件击碎,法阵的能量就是所有 连贯的元件能量和的最大值 。
老司机非常的自信,他有一套自己的破除法阵的方案(虽然不见得是最佳)
老司机希望能实时的关注着法阵的能量,一旦能量允许,他就破阵而入,救出女票。
忙着破阵的老司机自然没有功夫去计算他每步操作之后法阵的能量,他只能将此重任交与在座的各位大侠,请大家助他一臂之力。

Input

第一行n (1 ≤ n ≤ 100,000),为法力元件数量
第二行有n个数,为每个法力元件所含有的能量ei(0 ≤ ei ≤ 1e9)
第三行有n个数,为老司机击破法力元件的顺序

Output

输出n行,为老司机每次击破法力元件后法阵的能量。

Sample Input

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

Sample Output

6
5
5
1
0
8

18
16
11
8
8
6
6
0


解题心得:

  1. 别被题意给唬住了,可以去看看并查集的倒用,题意是叫你去将一个集合拆开,看起来很恐怖,其实完全是不需要的,只要按照拆开的顺序逆着来合并就可以了,运用一个并查集的知识,但是有也有要注意的东西,就是使用倒过来合并的时候叫你输出最大的能量顺序一开始应该是0,最后的那个所有能量的和其实是不存在的不应该输出,自己处理一下就好了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int num1[maxn],num2[maxn];
int father[maxn];
long long sum[maxn];
long long ans[maxn];
long long Max = 0;
bool vis[maxn];

int find(int x)
{
    if(father[x] == x)
        return x;
    else
        return father[x] = find(father[x]);
}

void merge(int a,int b)
{
    int fa = find(a);
    int fb = find(b);
    if(fa != fb)
    {
        father[fb] = fa;
        sum[fa] += sum[fb];//在集合合并的时候也要将他们的和加起来
    }
}

long long Find(int x)
{
    vis[x] = true;
    if(sum[x] > Max)
        Max = sum[x];
    if(vis[x+1])//如果它的上一个存在就合并
    {
        merge(x,x+1);
        if(sum[find(x)] > Max)
            Max = sum[find(x)];
    }
    if(vis[x-1])//下一个存在也合并
    {
        merge(x,x-1);
        if(sum[find(x)] > Max)
            Max = sum[find(x)];
    }
    return Max;//记录每次连接的最大值
}

int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {
        Max = 0;
        memset(vis,0,sizeof(vis));
        int t = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&num1[i]);
            sum[i] = num1[i];
            father[i] = i;
        }
        for(int i=1; i<=n; i++)
            scanf("%d",&num2[i]);//记录拆除的顺序
        ans[t++] = 0;//记录答案
        for(int i=n; i>=1; i--)
        {
            long long now;
            now = Find(num2[i]);
            ans[t++] = now;
        }
        for(int i=t-2; i>=0; i--)
            printf("%lld\n",ans[i]);
    }
}
posted @ 2017-07-24 21:17  GoldenFingers  阅读(158)  评论(0编辑  收藏  举报