Embiid  

题意:

给你一个环序列n个数,每个\(a_i\)有2个相邻的数,一次操作可以将\(a_i\)变为它和两个相邻数这三个数中最大的或者最小的。询问将n个数都变成1~m所需要的最小次数。

解法

我们先考虑对于一个单一的k,将n个数变成k。此时,有意义的条件只是比k大或者比k小,所以我们用-1表示小于k的数,0表示k,1表示比k大的数。很显然,只要有k就可以将整个序列变成k。
对于0 1 1或者0 -1 -1这样的,我们挨个将它变成0就可以了。我们需要考虑的是0 -1 1 -1 1这样交替变换的。显然我们需要多一次操作将-1 1变成-1 -1 或者1 1然后依次变成0。一个长度为L的交替变换序列,我们需要多\(\lfloor {\frac{L}{2}}\rfloor\)次操作。因此我们将n个数变为k的所需次数\(f(k)=num(-1)+num(1)+\sum_{L} {\lfloor {\frac{L}{2}}\rfloor}\)
这样我们通过O(n)可以求出一个值,那么k每次加一,就会将k从0变成-1,k+1从1变成0。线段树修改查询就可以在O(mlogn)的复杂度内求出所有答案。

#include <bits/stdc++.h>
#define pb emplace_back
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;

const int maxn = 4e5;
vector <int> pos[maxn + 11];
int a[maxn + 11];
struct node{
	int l,r,ans;
}tree[4 * maxn + 11];
int sta = 0;
node merge(node A,node B,int l,int r,int mid) {
	node ret;
	bool flag = 1ll * (a[mid] - sta) * (a[mid + 1] - sta) < 0 ? true : false;
	if (A.l == mid - l + 1 && flag) {
		ret.l = A.l + B.l;
	}
	else ret.l = A.l;
	if (B.r == r - mid && flag) {
		ret.r = A.r + B.r;
	}
	else ret.r = B.r;
	if (flag)
		ret.ans = A.ans - A.r / 2 + B.ans - B.l / 2 + (A.r + B.l) / 2;
	else ret.ans = A.ans + B.ans;
	return ret;
} 

void build(int rt,int l,int r) {
	if (l == r) {
		if (a[l] == sta) tree[rt] = {0 , 0 , 0};
		else tree[rt] = {1 , 1 , 0};
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson , l , mid);
	build(rson , mid + 1 , r);
	tree[rt] = merge(tree[lson] , tree[rson] , l , r , mid);
}

void update(int rt,int l,int r,int pos) {
	if (l > pos || r < pos) return;
	if (l == r) {
		if (a[l] == sta) tree[rt] = {0 , 0 , 0};
		else tree[rt] = {1 , 1 , 0};
		return;
	}
	int mid = (l + r) >> 1;
	update(lson , l , mid , pos);
	update(rson , mid + 1 , r , pos);
	tree[rt] = merge(tree[lson] , tree[rson] , l , r , mid);
}

node query(int rt,int l,int r,int al,int ar) {
	if (l >= al && r <= ar) {
		return tree[rt];
	}
	int mid = (l + r) >> 1;
	if (mid >= ar) return query(lson , l , mid , al , ar);
	if (al > mid) return query(rson , mid + 1 , r , al , ar);
	return merge(query(lson , l , mid , al , ar) , query(rson , mid + 1 , r , al , ar) , max(l , al) , min(r , ar) , mid);
} 

int main(){
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		pos[a[i]].pb(i);
	}
	for (int i = n + 1; i <= 2 * n; i++) a[i] = a[i - n];
	build(1 , 1 , 2 * n);
	for (int i = 1; i <= m; i++) {
		sta = i;
		for (auto p : pos[i]) {
			update(1 , 1 , 2 * n , p); update(1 , 1 , 2 * n , p + n);
		}
		for (auto p : pos[i - 1]) {
			update(1 , 1 , 2 * n , p); update(1 , 1 , 2 * n , p + n);
		}
		if (pos[i].empty()) {
			printf("-1 ");
			continue;
		}
		int l = pos[i][0]; int r = pos[i][0] + n;
		int ret = query(1 , 1 , 2 * n , l , r).ans;
		printf("%d " , ret + n - (int)pos[i].size());
	} 
} 

posted on 2020-03-19 17:47  Embiid  阅读(700)  评论(0编辑  收藏  举报