CodeForces 722C Destroying Array (并查集)

题意:给定 n 个数,然后每次破坏一个位置的数,那么剩下的连通块的和最大是多少。

析:用并查集来做,从后往前推,一开始什么也没有,如果破坏一个,那么我们就加上一个,然后判断它左右两侧是不是存在,如果存在,那么就合并起来,

然后不断最大值,因为这个最大值肯定是不递减,所以我们一直更新就好。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
//#include <tr1/unordered_map>
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;
//using namespace std :: tr1;

typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const LL LNF = 0x3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e5 + 5;
const LL mod = 10000000000007;
const int N = 1e6 + 5;
const int dr[] = {-1, 0, 1, 0, 1, 1, -1, -1};
const int dc[] = {0, 1, 0, -1, 1, -1, 1, -1};
const char *Hex[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
inline LL gcd(LL a, LL b){  return b == 0 ? a : gcd(b, a%b); }
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline int Min(int a, int b){ return a < b ? a : b; }
inline int Max(int a, int b){ return a > b ? a : b; }
inline LL Min(LL a, LL b){ return a < b ? a : b; }
inline LL Max(LL a, LL b){ return a > b ? a : b; }
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}
int a[maxn], b[maxn], p[maxn];
bool num[maxn];
vector<LL> ans;
LL ran[maxn];

int Find(int x) {  return x == p[x] ? x : p[x] = Find(p[x]); }

int main(){
    while(scanf("%d", &n) == 1){
        for(int i = 1; i <= n; ++i){  scanf("%d", a+i); p[i] = i; }
        for(int i = 1; i <= n; ++i)  scanf("%d", b+i);

        ans.clear();
        memset(num, false, sizeof num);
        LL cnt = 0;
        for(int i = n; i > 0; --i){
            ans.push_back(cnt);
            int x = b[i];
            num[x] = true;
            ran[x] = a[x];
            if(num[x+1]){
                int y = Find(x+1);
                p[y] = x;
                ran[x] += ran[y];
            }
            if(num[x-1]){
                int y = Find(x-1);
                p[y] = x;
                ran[x] += ran[y];
            }
            cnt = Max(cnt, ran[x]);
        }

        for(int i = ans.size()-1; i >= 0; --i)
            printf("%I64d\n", ans[i]);
    }
    return 0;
}
时间: 2024-10-17 07:43:22

CodeForces 722C Destroying Array (并查集)的相关文章

C. Destroying Array 并查集,逆向思维

用并查集维护线段,从后往前枚举没个删除的位置id[i] 那么,现在删除了这个,就是没有了的,但是上一个id[i + 1]就是还没删除的. 然后现在进行合并 int left = id[i + 1];(相当于每次都加入一个元素a[left]) 它在这个位置,如果能和左右的合并,就是左右邻居都有元素,那么当然是合并最好,因为元素都是大于0的,越长越好. 合并的时候再记录一个数组sum[pos]表示以这个为根的总和是多少.按并查集的思路更新整个并查集即可. 注意一点的就是, 要求ans[i] 那么an

CodeForces 722C Destroying Array

并查集,离线操作. 将操作倒着进行,一开始所有数字都没有加入到数组中,然后倒着一个一个加入,更新最大值. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map>

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

题目大意就是给一个初始数组,每次删除一个点,问你剩下的连续的那些点中,最大的和是多少 2种做法 第一种是离线并查集  (这里是不会用那个res[]数组,将子的权值挪给父亲那里. 第二种是线段树区间合并.(练手 ///线段树 1 #include <algorithm> 2 #include <stack> 3 #include <istream> 4 #include <stdio.h> 5 #include <map> 6 #include &

Codeforces 722C Destroying Array(并查集)*

题目链接:http://codeforces.com/problemset/problem/722/C 题意: 有 n 个正整数序列.同时 n 个摧毁序列,从 1 到 n每次把正整数序列里对应下标的数字去掉,成为一个间隔. 问每去掉一个数字,序列中最大的连续子段和. 思路: 倒着想,这道题就变成了:从 n 到 1每次出现一个数字,若数字的两边已经存在集合,则把存在的集合合并为一个, 并更新集合的和,否则单独为一个集合.过程中始终维护序列中目前所有集合里和的最大值. 代码: #include <i

CodeForces-722C Destroying Array 并查集 离线操作

题目链接:https://cn.vjudge.net/problem/CodeForces-722C 题意 给个数组,每次删除一个元素,删除的元素作为一个隔断,问每次删除后该元素左右两边最大连续和 思路 这个题的思路马上就想到的时候,别人直接抢答,还是比较厉害的人了 离线操作,删除变成添加,添加时注意左右两边元素的最大值即可 提交过程 WA 忘了为什么WA了 AC 代码 #include <cstdio> #include <algorithm> using namespace s

codeforces 468B two set(并查集)

codeforces 468B two set(并查集)n+1 表示 B 组 n+2 表示 A 组 按照 这题的做法 应该是 如果 满足 num[ i ] a-num[ i ] 则他们同一组 但不一定 就一定是 都是 A 组 也可能都是 B 组 然而如果不满足这个条件的话,就直接加入 B组 然后如果满足 num[ i ] b-num[ i ] 则加入同一组 然后不满足就 加入 A 组 1 #include <bits/stdc++.h> 2 using namespace std ; 3 4

Codeforces 278C Learning Languages(并查集) 求连通块

Codeforces 278C Learning Languages(并查集) 求连通块 为什么最后还要getfather 一遍 比如 x 是 y 的父亲 然后你 Union(x,z) 然后 z 变成了 x 父亲 然后 y 的祖先就是错的了 题解 求一个无向图中有几个连通块 sum 特判 一下 如果 每一个人的语言都为 0 则答案为 sum 其他 答案则为 sum - 1 1 #include <bits/stdc++.h> 2 using namespace std ; 3 4 const

Codeforces 292D Connected Components (并查集)

Codeforces 292D Connected Components (并查集) 题意 给出一张无向图,每次询问删去第Li--Ri 条边 求此时有多少个连通块 题解 求出一个前缀 Li 表示 加入前 i 条边时图的连通状况 以及一个后缀 Ri 表示 加入后 i 条边时图的连通状况 对于每个询问 删除 s--t 条边 只要将 L s-1 和 R t+1 合并 一下 就行了 合并 其实 就是讲 s-1 和 t+1 对应的 f[ i ] Union 一下就行了 为什么 这就相当于把前缀 i 和 后

Codeforces Gym 100463E Spies 并查集

Spies Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Description In the aftermath of Canada’s annexation of Pittsburgh tensions have been pretty high between Canada and the US. You have personally been hired