您的位置:首页 > 其它

Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array(并查集)

2016-10-02 01:41 411 查看
题意:给定一个自然数序列An,和(1~n)的下标序列Bn,Bn代表每次要销毁的数字的下标,求前i次销毁后,最大的子段和是多少?

题解:并查集。我们从后往前恢复,把Bi-1和Bi联合,Bi+1和Bi联合,那么sum[B[i]] = sum[B[i]-1] + sum[B[i]+1] + A[B[i]];

#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <iostream>
#include <cstring>
#include <algorithm>

#define LL unsigned long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define clr(a,b) memset(a,b,sizeof a)
#define sd(x) scanf("%d",&x)
#define sf(x) scanf("%lf",&x)
#define ss(x) scanf("%s",x)
#define x first
#define y second
#define INF 0x3f3f3f3f
#define MAXN 200005
using namespace std;
LL a[MAXN];
int d[MAXN];
int f[MAXN];
int vis[MAXN];
LL sum[MAXN];
stack<LL> S;
int getf(int x)
{
if(x != f[x]) f[x] =getf(f[x]);
return f[x];
}
void union_set(int a,int b)
{
a = getf(a);
b = getf(b);
if(a!=b) f[a] = b;
}
void solve()
{
int n;
scanf("%d",&n);
rep(i,1,n) f[i] =i;
rep(i,1,n)
scanf("%I64d",&a[i]);
rep(i,1,n)
scanf("%d",&d[i]);
S.push(0);
LL mx = 0;
per(i,n,2)
{
vis[d[i]] = 1;
sum[d[i]] = a[d[i]];
if(vis[d[i]-1]) sum[d[i]] += sum[getf(d[i]-1)],union_set(d[i]-1,d[i]);
if(vis[d[i]+1]) sum[d[i]] += sum[getf(d[i]+1)],union_set(d[i]+1,d[i]);
mx = max(mx,sum[d[i]]);
 S.push(mx);
}
while(!S.empty())
{
printf("%I64d\n",S.top());
S.pop();
}
}
int main()
{
solve();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐