CF1514D Cut and Stick 题解

题目传送门

前置知识

可持久化线段树

解法

若区间内不存在绝对众数,直接保持这一段即可。

若存在绝对众数,贪心地想肯定要尽可能地把其分开还要限制出其他数使其不成为绝对众数。容易发现设绝对众数出现次数为 \(cnt\),取 \(cnt-1\) 个其他数和绝对众数配对最优。但可能其他数不够 \(cnt\) 个,就只能让多余的绝对众数各成一组了。最终答案即为 \(2cnt-(r-l+1)\)

主席树求下是否存在绝对众数及其出现次数即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
int a[300010];
struct PDS_SMT
{
	int root[300010],rt_sum;
	struct SegmentTree
	{
		int ls,rs,sum;
	}tree[300010<<5];
	#define lson(rt) tree[rt].ls
	#define rson(rt) tree[rt].rs
	int build_rt()
	{
		rt_sum++;
		return rt_sum;
	}
	void build_tree(int &rt,int l,int r)
	{
		rt=build_rt();
		if(l==r)
		{
			return;
		}		
		int mid=(l+r)/2;
		build_tree(lson(rt),l,mid);
		build_tree(rson(rt),mid+1,r);
	}
	void update(int pre,int &rt,int l,int r,int pos)
	{
		rt=build_rt();
		tree[rt]=tree[pre];
		tree[rt].sum++;
		if(l==r)
		{
			return;
		}
		int mid=(l+r)/2;
		if(pos<=mid)
		{
			update(lson(pre),lson(rt),l,mid,pos);
		}
		else
		{
			update(rson(pre),rson(rt),mid+1,r,pos);
		}
	}
	int query(int rt1,int rt2,int l,int r,int k)
	{
		if(l==r)
		{
			return tree[rt2].sum-tree[rt1].sum;
		}
		int mid=(l+r)/2;
		if(tree[lson(rt2)].sum-tree[lson(rt1)].sum>k)
		{
			return query(lson(rt1),lson(rt2),l,mid,k);
		}
		if(tree[rson(rt2)].sum-tree[rson(rt1)].sum>k)
		{
			return query(rson(rt1),rson(rt2),mid+1,r,k);
		}
		return 0;
	}
}T;
int main()
{
	int n,m,l,r,cnt,i;
	scanf("%d%d",&n,&m);
	T.build_tree(T.root[0],1,n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		T.update(T.root[i-1],T.root[i],1,n,a[i]);
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&l,&r);
		cnt=T.query(T.root[l-1],T.root[r],1,n,(r-l+1)/2.0);
		if(cnt==0)
		{
			printf("1\n");
		}
		else
		{
			printf("%d\n",2*cnt-(r-l+1));
		}
	}
	return 0;
}
posted @ 2024-08-23 20:36  hzoi_Shadow  阅读(9)  评论(1编辑  收藏  举报
扩大
缩小