Codeforces 722C(并查集 + 思维)

题目链接:http://codeforces.com/problemset/problem/722/C

思路:

  题目给的操作数从第 1 个到第 N 个数是删除原数组中的一个数, 那么反过来从后往前就是增加原数组中的一个数, 每增加一个值, 那么就有四种情况: 第一种和前后都不连续, 即自成一个集合; 第二种:和前面的数连续, 即和前一个数在一个集合; 第三种和之后一个数连续, 即和之后的一个数在一个集合; 第四种既和前面一个数连续也和后面一个数连续,那么说明前后两个集合被这个数合并成一个集合. 然后合并的时候维护每个集合的元素和 sum, 利用 max 记录当前集合 sum 和新增集合的 sum 中的最大值.

代码:

 1 #include <bits/stdc++.h>
 2
 3 typedef long long LL;
 4 const int MAXN = 100000;
 5 using namespace std;
 6 LL pre[MAXN + 3], cnt[MAXN + 3], a[MAXN + 3], pos[MAXN + 3], visit[MAXN + 3], ans[MAXN + 3];
 7
 8 int Find(int x) { return x == pre[x] ? x : pre[x] = Find(pre[x]); }
 9
10 void mix(int x, int y) {
11     int fx = Find(x), fy = Find(y);
12     if(fx != fy) pre[fy] = fx, cnt[fx] += cnt[fy]; //合并两个集合的同时维护新集合的 sum
13 }
14
15 int main() {
16     ios_base::sync_with_stdio(0); cin.tie();
17     int n; cin >> n;
18     for(int i = 1; i <= n; i++) {
19         cin >> a[i];
20         pre[i] = i, visit[i] = 0;
21     }
22     for(int i = 0; i < n; i++) cin >> pos[i];
23     LL maxn = 0;
24     for(int i = n - 1; i >= 0; i--) {
25         int tp = pos[i];
26         cnt[tp] = a[tp], visit[tp] = 1, ans[i] = maxn;
27         if(tp != 1 && visit[tp - 1]) mix(tp, tp - 1); // 新增一个元素后形成的四种情况
28         if(tp != n && visit[tp + 1]) mix(tp, tp + 1);
29         maxn = max(maxn, cnt[ Find(tp) ]);
30     }
31     for(int i = 0; i < n; i++) cout << ans[i] << endl;
32     return 0;
33 }
时间: 2024-10-12 12:18:30

Codeforces 722C(并查集 + 思维)的相关文章

Codeforces 200A Cinema 并查集 + 思维 (看题解)

Cinema 感觉这个题好神啊... 首先如果 n 比 m 大, 我们先旋转90度. 我们要加入一个(x, y)的时候, 我们枚举答案所在的行离 x 的距离 g , 然后对于x + g 行来说 我们找到(x + g, y)左边的第一个和右边的第一个未被占的位置,更新答案, 如果 g > 答案 退出. 左边和右边第一个未被占的可以用并查集维护, 把连续占了的并成一个联通块, 维护最小值和最大值. 对于 2000 * 2000的图来说, 对于每一次, 最多sqrt( n )就能找到答案, 因为最坏情

CodeForces - 763A(并查集/思维)

题意 https://vjudge.net/problem/CodeForces-763A 一棵无根树中各个节点被染上了一种颜色c[i] 现在让你选择一个点作为根节点,使得这个根节点的所有儿子满足以该儿子节点的作为根的子树中所有点颜色均相同(不同儿子为根的子树颜色可以不同) 思路 俺的方法: 暴力水过.用并查集把相同颜色的连了边的点缩点,然后枚举每个点作为答案,判断这个点所连的的所有点的所在相同颜色连通块的大小之和是否等于n-1即可(除去自己这个点). 正解: 先计算每个点与所连的点的颜色不同的

codeforces 366D 并查集

//给你一个无向图,图的每条边有一个范围,所选数x要在这个范围能过这条边 //求x最大范围 //枚举所有的边的右边,对于所选右边找左边最小值,用并查集判断是否可行 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std ; const int maxn = 1010; int F[maxn] ; int find(int x)

并查集+思维——X-Plosives

一.问题描述(题目链接) 有n种化合物,每种化合物由两种元素组成.当几种的化合物数量等于他们所含不同元素的数量时,就会发生爆炸.现在依次给出化合物的组成,当新的化合物与之前的化合物放在一起会发生爆炸时,就不能允许这个化合物放进来.输出拒绝的次数. 二.问题分析 把元素看成点,化合物看成边,每次新的化合物进来当成连一条边. 如果图中没有环,则每个连通分量是一棵树,其边数等于点数减1,不可能存在爆炸的情况:如果图中有环,则这个环上点数等于边数,就会爆炸. 使用并查集连边,如果要连的两个点在同一集合中

并查集+思维——The Door Problem

一.问题描述(题目链接) 有n个门和m个开关,每个开关可以控制任意多的门,每个门严格的只有两个开关控制,问能否通过操作某些开关使得所有门都打开.(给出门的初始状态). 二.问题分析 大部分开关问题首先要想到的一点就是任何开关操作两次以上都是无意义的,因此对于每个开关,我们要么操作一次,要么不操作. 因为已知门的初始状态,每个门由两个开关控制,所以我们可以调节这两个开关,使门保持打开的状态. 我们考虑用并查集维护开关之间的关系,因为每个开关有操作和不操作两种状态.,因此,我们要把每个点拆成两个点,

0-1-Tree CodeForces - 1156D (并查集)

大意: 给定树, 边权为黑或白, 求所有有向路径条数, 满足每走过一条黑边后不会走白边. 这题比赛的时候想了个假算法, 还没发现..... 显然所求的路径要么全黑, 要么全白, 要么先全白后全黑, 所以可以用并查集将相邻同色边合并即可. #include <iostream> #include <random> #include <algorithm> #include <cstdio> #include <math.h> #include &l

并查集+思维——Destroying Array

一.题目描述(题目链接) 给定一个序列,按指定的顺序逐一删掉,求连续子序列和的最大值.例如序列1 3 2 5,按3 4 1 2的顺序删除,即依次删除第3个.第4个.第1个.第2个,答案为5 4 3 0. 二.问题分析 我们知道从并查集中删除元素很难,而合并非常简单.所以我们可以反过来思考,正向删除元素等同于反向添加元素,将结果存起来反向输出即可.每次添加一个元素,更新最大值.很明显新加入的点只影响相邻元素的值.每添加一个元素有4种情况:单独成集合,只与前面的成集合,只与后面的成集合,既与前面的成

CodeForces 566D 并查集集合合并

1 #include <stdio.h> 2 #include <algorithm> 3 #define MAX 100000 4 #define LL long long 5 #define unsigned U 6 //using namespace std; 7 int cas=1,T; 8 int fa[MAX*2+10],next[MAX*2+10],n,q; 9 void init(int n) 10 { 11 for(int i=1;i<=n;i++) { f

codeforces 455C 并查集

传送门 给n个点, 初始有m条边, q个操作. 每个操作有两种, 1是询问点x所在的连通块内的最长路径, 就是树的直径. 2是将x, y所在的两个连通块连接起来,并且要合并之后的树的直径最小,如果属于同一个连通块就忽视这个操作. 先dfs出每个连通块的初始直径, 然后合并的话就是len[x] = max( (len[x]+1)/2+(len[y]+1)/2+1, max(len[x], len[y]));  然后搞一搞就好了. 一开始写bfs写挫了一直超时,  只好改成dfs...... 1 #