SEERC 2019 A.Max or Min


題意:

給你一個環序列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());
	} 
} 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM