您的位置:首页 > 其它

codeforces 722 C Destroying Array (逆向思维+并查集 || STL模拟)

2016-11-19 19:37 477 查看
You are given an array consisting of n non-negative integersa1, a2, ..., an.

You are going to destroy integers in the array one by one. Thus, you are given the permutation of integers from1 to
n defining the order elements of the array are destroyed.

After each element is destroyed you have to find out the segment of the array, such that it contains no destroyed elements and the sum of its elements is maximum possible. The sum of elements in the empty segment is considered to be0.

Input
The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the length of the array.

The second line contains n integers
a1, a2, ..., an (0 ≤ ai ≤ 109).

The third line contains a permutation of integers from
1 to n — the order used to destroy elements.

Output
Print n lines. The
i-th line should contain a single integer — the maximum possible sum of elements on the segment containing no destroyed elements, after firsti operations are performed.

Examples

Input
4
1 3 2 5
3 4 1 2


Output
5
4
3
0


Input
5
1 2 3 4 5
4 2 3 5 1


Output
6
5
5
1
0


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


Output
18
16
11
8
8
6
6
0


Note
Consider the first sample:

Third element is destroyed. Array is now 1 3  *  5. Segment with maximum sum5 consists of one integer
5.
Fourth element is destroyed. Array is now 1 3  *   * . Segment with maximum sum4 consists of two integers
1 3.
First element is destroyed. Array is now  *  3  *   * . Segment with maximum sum3 consists of one integer
3.
Last element is destroyed. At this moment there are no valid nonempty segments left in this array, so the answer is equal to0.

题意:

给你n个数,每次摧毁一个,求每摧毁一个的最大连续和(被摧毁的点的两边不连续)。

1 3 2 5

摧毁位置3:1,3,*,5 max=5

摧毁位置4:1,3,*,* max=4

摧毁位置1:*,3,*,* max=3

摧毁位置2:*,*,*,* max=0

下次遇到摧毁问题,我们可以逆向思维,现附上超时代码

#include<bits/stdc++.h>
using namespace std;
set<int>ss;
set<int>::iterator it;
const int N = 1e5+10;
typedef long long ll;
int a
,b
;
ll pre
;
int main()
{
ios::sync_with_stdio(false);
int n,i,j,p,last;
cin>>n;
for(i=1;i<=n;i++) {
cin>>a[i];
pre[i]=(ll) pre[i-1]+a[i];
}
for(i=1;i<=n;i++) {
ll ans=0;
last=0;
cin>>b[i];
ss.insert(b[i]);
for(it=ss.begin();it!=ss.end();it++) {
p=*it;
ans=max(ans,pre[p-1]-pre[last]);
last=p;
}
ans=max(ans,pre
-pre[last]);
cout<<ans<<endl;
}

return 0;
}


思路:将操作倒着进行,一开始所有数字都没有加入到数组中,然后倒着一个一个加入,更新最大值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int a
,b
,fa
,vis
;
ll sum
;
stack<ll>s;
int find(int x)
{
int r=x;
while(fa[r]!=r) r=fa[r];
int i=x,j;
while(i!=r) {
j=fa[i];
fa[i]=r;
i=j;
}
return r;
}
int main()
{
ios::sync_with_stdio(false);
int n,i,j;
int x,y,fx,fy;
ll ans=0;
cin>>n;
for(i=1;i<=n;i++) {
cin>>a[i];
fa[i]=i;
sum[i]=a[i];
}
for(i=1;i<=n;i++) cin>>b[i];
for(i=n;i>1;i--) {
x=b[i];
vis[x]=1;
ans=max(ans,(ll)a[x]);
y=b[i]-1;
if(y>0 && vis[y]) {
fx=find(x);
fy=find(y);
if(fx!=fy) {
fa[fx]=fy;
sum[fy]+=sum[fx];
ans=max(ans,sum[fy]);
}
}
y=b[i]+1;
if(y<=n && vis[y]) {
fx=find(x);
fy=find(y);
if(fx!=fy) {
fa[fx]=fy;
sum[fy]+=sum[fx];
ans=max(ans,sum[fy]);
}
}
s.push(ans);
}
while(!s.empty()) {
cout<<s.top()<<endl;;
s.pop();
}
cout<<"0"<<endl;
}


灵活运用STL的做法

用set来存区间,一开始的区间是[1, n],删除一个数后,去掉[1, n]区间,存入[1, b[1]-1]跟[b[1]+1, n]这两个区间。

每去掉一个区间就加上两个区间

用multi_set来存区间和,每次删掉相应的一个区间和,加上两个区间和,然后输出最大值

用set<pair<终点, 起点> >s来存区间和

用set< pair<int,int> > ::iterator it=s.lower_bound(make_pair(b[i],1))找区间

#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int N=1e5+10;

ll sum
, a
, ans
;
int b
;

set<pair<int, int> >s;
set<pair<int, int> > :: iterator it;
multiset<ll>ms;

int main(){
int n;
scanf("%d", &n);
sum[0] = 0;
for(int i=1; i<=n; i++) scanf("%I64d", &a[i]), sum[i] = sum[i-1]+a[i];
for(int i=1; i<=n; i++) scanf("%d", &b[i]);

s.clear(), ms.clear();
s.insert(make_pair(n, 1)), ms.insert(sum
);

for(int i=1; i<=n; i++){
it = s.lower_bound(make_pair(b[i], 1));
int r = it->first, l = it->second;
s.erase(*it);
s.insert(make_pair(b[i]-1, l)), s.insert(make_pair(r, b[i]+1));

ms.erase(ms.find(sum[r]-sum[l-1]));
ms.insert(sum[b[i]-1]-sum[l-1]), ms.insert(sum[r]-sum[b[i]]);

multiset<ll>:: reverse_iterator reit = ms.rbegin();
printf("%I64d\n", *reit);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: