CF1326E Bombs

Posted ereoth

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1326E Bombs相关的知识,希望对你有一定的参考价值。

Problem

给定两个长度均为 \\(n\\) 的排列 \\(p,q\\) 。对一个初始为空的集合 \\(s\\) 进行如下操作:对于每个 \\(i\\) ,将 \\(p_i\\) 放入集合;如果 \\(i\\)标记了,则此时再将集合中最大的数删除。求 \\(n\\) 次操作后集合中最大的数。

排列 \\(q\\) 的意义是,对于每个 \\(i\\) ,询问将 \\(q_1,q_2\\cdots q_i-1\\) 都标记之后的上述操作的结果。

\\(1\\leq n\\leq 3\\times 10^5,1 \\leq p_i,q_i \\leq n\\)

Input

第一行输入一个整数 \\(n\\)
第二行输入 \\(n\\) 个数 \\(p_1,p_2\\cdots p_n\\)
第三行输入 \\(n\\) 个数 \\(q_1,q_2\\cdots q_n\\)

Output

输出一行 \\(n\\) 个整数表示答案。

Sample

Input 1

3
3 2 1
1 2 3

Output 1

3 2 1

Input 2

6
2 3 6 1 5 4
5 2 1 4 6 3

Output 2

6 5 5 5 4 1

Solution

容易看出答案是单调不增的。

考虑当前答案为 \\(res\\),我们发现答案变小当且仅当不存在任意一个下标满足它右边不小于 \\(res\\) 的数比它右边的炸弹数多

然后就很好做了,把添加炸弹当作 \\(-1\\) 的贡献,把删数更新答案当作 \\(+1\\) 的贡献,线段树维护下即可。

代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int kmax = 3e5 + 3;

struct T 
  int s, laz;
 t[kmax << 2];

int n, a[kmax], b[kmax];
int p[kmax];
int res;

void Pushup(int x) 
  t[x].s = max(t[x << 1].s, t[x << 1 | 1].s);


void Pushdown(int x) 
  if (!t[x].laz) return;
  t[x << 1].laz += t[x].laz, t[x << 1 | 1].laz += t[x].laz;
  t[x << 1].s += t[x].laz, t[x << 1 | 1].s += t[x].laz;
  t[x].laz = 0;


void Modify(int x, int l, int r, int _l, int _r, int v)  // 线段树区间修改
  if (_l <= l && r <= _r) 
    t[x].s += v;
    t[x].laz += v;
    return;
  
  Pushdown(x);
  int mid = (l + r) >> 1;
  if (_l <= mid) Modify(x << 1, l, mid, _l, _r, v);
  if (_r > mid) Modify(x << 1 | 1, mid + 1, r, _l, _r, v);
  Pushup(x);


int main() 
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n;
  res = n;
  for (int i = 1; i <= n; i++) 
    cin >> a[i];
    p[a[i]] = i; // 记录下每个值所在的位置
  
  for (int i = 1; i <= n; i++) 
    cin >> b[i];
  
  cout << n << \' \'; // 最开始答案显然为n
  Modify(1, 1, n, 1, p[n], 1); // 修改
  for (int i = 1; i < n; i++) 
    for (Modify(1, 1, n, 1, b[i], -1); t[1].s <= 0; Modify(1, 1, n, 1, p[--res], 1))  // 添加炸弹,如果不存在符合要求的,更新答案
    
    cout << res << \' \';
  
  return 0;

uva 10765 Doves and Bombs(割顶)

??

题意:给定一个n个点的连通的无向图,一个点的“鸽子值”定义为将它从图中删去后连通块的个数。求每一个点的“鸽子值”。

思路dfs检查每一个点是否为割顶,并标记除去该点后有多少个连通分量

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<cstdlib>  
#include<iostream>  
#include<algorithm>  
#include<vector>  
#include<map>  
#include<queue>  
#include<stack> 
#include<string>
#include<map> 
#include<set>
#define eps 1e-6 
#define LL long long  
using namespace std;  

const int maxn = 10000 + 100;
const int INF = 0x3f3f3f3f;
int n, m;
vector<int> G[maxn];
int val[maxn], node[maxn]; //node数组记录结点id间接排序 
bool cmp(int x, int y) {
	return val[x] == val[y] ? x < y : val[x] > val[y];
}

int pre[maxn], dfs_clock;
int dfs(int u, int fa) { //u在dfs树中的父节点为fa 
	int lowu = pre[u] = ++dfs_clock;
	int child = 0;        //子节点个数 
	for(int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		if(!pre[v]) {   //没有訪问过v 
			child++;
			int lowv = dfs(v, u);
			lowu = min(lowu, lowv);    //用后代的low函数更新u的low函数 
			if(lowv >= pre[u]) {
				val[u]++;
			}
				
		}
		else if(pre[v] < pre[u] && v != fa)  lowu = min(lowu, pre[v]);  //用反向边更新u的low函数 
	} 
	if(fa < 0 && child == 1) val[u] = 1;
	return lowu; 
} 


void init() {
	dfs_clock = 0;
	memset(pre, 0, sizeof(pre));
	for(int i = 0; i < n; i++) {
		G[i].clear();
		node[i] = i;
		val[i] = 1;
	}
	int x, y;
	while(scanf("%d%d", &x, &y) == 2 && x >= 0) {
		G[x].push_back(y);
		G[y].push_back(x);
	}
}

void solve() {
	dfs(0, -1);
	sort(node, node+n, cmp);
	for(int i = 0; i < m; i++) cout << node[i] << " " << val[node[i]] << endl; 
	cout << endl;
}

int main() {
	//freopen("input.txt", "r", stdin);
	while(scanf("%d%d", &n, &m) == 2 && n) {
		init();
		solve();
	}
	return 0;
}










以上是关于CF1326E Bombs的主要内容,如果未能解决你的问题,请参考以下文章

Bombs CodeForces - 1326E 线段树

codechef Little Elephant and Bombs题解

uva 10765 Doves and Bombs(割顶)

Defuse the Bombs Gym - 102822D

UVA10765Doves and bombs (BCC求割点后联通块数量)

[逆向工程]二进制 Bianry Bombs 快乐拆弹