[海军国际项目办公室]羽未

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]羽未相关的知识,希望对你有一定的参考价值。

羽未

题目概述


题解

T i w A i r O A O \\rm\\colorblackT\\colorrediwAirOAO TiwAirOAO:这不就是一个线段树基础练习题吗

首先,对于一个固定的序列 a a a,我们很容易想到一种贪心地求解思路。
我们将一种颜色最左端的点到最右端的点所覆盖的区间看成这种颜色的区间,显然,区间有交的两种颜色必定都要变成同一种颜色。
我们将区间有交的区间看成一个区间连通块,一个区间联通块的点都要变成一种颜色,显然变成该联通块内点数最多的那种颜色是最优的。
我们可以贪心地将所有区间按左端点排序,然后求出所有的区间连通块以及其的点数最多的颜色。
显然,由于我们每次修改最多会给两个区间造成影响,我们可以暴力将这些区间重排。实际上将全部都sort一遍也不会T
时间复杂度 O ( ∣ C ∣ q ) O\\left(|C|q\\right) O(Cq),可以有 70 70 70pts。

显然,我们可以用数据结构对上面的过程进行优化。
我们考虑如何维护一个区间连通块。
显然,两个区间联通块区别的地方在于它们相邻处是两个没有共同区间覆盖的点。
我们可以维护哪些相邻的两个点是有共同区间将其覆盖住的。
我们每次颜色区间的改变相当于改变我们区间覆盖的范围。
由于一个点可能同时被多个点覆盖住,不妨维护一个点被多少个区间覆盖住,由于我们每次修改都是进行区间的加减,我们不妨就维护区间内最小值划分整个区间。
显然,一个点不可能被负数个区间所覆盖住,我们要的没有共同区间覆盖的相邻点划分区间,可以看成被 0 0 0个全进所覆盖的点,该值如果有的话一定是最小的。
对于每个被划分的区间,我们需要维护该区间内的最大值。
相当于我们整个在线段树上维护被最小值划分开来区间的最大值和。
这显然就是个线段树的经典问题了,我们只需要多维护一个前后缀划分最大值就行了。

时间复杂度 O ( ( n + q ) log ⁡   n ) O\\left((n+q)\\log\\,n\\right) O((n+q)logn)

源码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 200005
#define mkpr make_pair 
#define pb push_back
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f; 
 
template<typename _T>
void print(_T x)if(x>9)print(x/10);putchar(x%10+'0');
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int n,q,a[MAXN],b[MAXN<<1],totb,L[MAXN],R[MAXN],val[MAXN],totd;
set<int>s[MAXN];
struct mingint i,x;p[MAXN];
struct tannint l,r,w;d[MAXN];
struct node
	int lmx,rmx,maxx,sum,minn;
	node()lmx=rmx=maxx=sum=minn=0;
;
node merge(node x,node y)
	node res;res.minn=min(x.minn,y.minn);
	res.maxx=max(x.maxx,y.maxx);
	if(x.minn<y.minn)
		res.lmx=x.lmx,res.rmx=max(x.rmx,y.maxx),res.sum=x.sum;
	else if(x.minn>y.minn)
		res.lmx=max(x.maxx,y.lmx),res.rmx=y.rmx,res.sum=y.sum;
	else res.lmx=x.lmx,res.rmx=y.rmx,res.sum=x.sum+y.sum+max(x.rmx,y.lmx); 
	return res;

class SegmentTree
	private:
		int lzy[MAXN<<2];node tr[MAXN<<2];
		void pushup(int rt)tr[rt]=merge(tr[lson],tr[rson]);
		void pushdown(int rt)
			if(lzy[rt])
				lzy[lson]+=lzy[rt];tr[lson].minn+=lzy[rt];
				lzy[rson]+=lzy[rt];tr[rson].minn+=lzy[rt];
				lzy[rt]=0;
			
		
	public:
		void modify(int rt,int l,int r,int al,int ar,int aw)
			if(ar<l||al>ar||l>r||al>ar)return ;
			if(al<=l&&r<=ar)lzy[rt]+=aw;tr[rt].minn+=aw;return ;
			int mid=l+r>>1;pushdown(rt);
			if(al<=mid)modify(lson,l,mid,al,ar,aw);
			if(ar>mid)modify(rson,mid+1,r,al,ar,aw);
			pushup(rt);
		
		void insert(int rt,int l,int r,int ai,int aw)
			if(l>r||l>ai||r<ai)return ;
			if(l==r)tr[rt].sum=tr[rt].maxx=aw;tr[rt].lmx=tr[rt].rmx=0;return ;
			int mid=l+r>>1;pushdown(rt);
			if(ai<=mid)insert(lson,l,mid,ai,aw);
			if(ai>mid)insert(rson,mid+1,r,ai,aw);
			pushup(rt);
		
		int query()return (tr[1].minn==0)*(tr[1].lmx+tr[1].rmx+tr[1].sum);
T;
int main()
	freopen("umi.in","r",stdin);
	freopen("umi.out","w",stdout);
	read(n);read(q);
	for(int i=1;i<=n;i++)read(a[i]),b[++totb]=a[i];
	for(int i=1;i<=q;i++)read(p[i].i),read(p[i].x),b[++totb]=p[i].x;
	sort(b+1,b+totb+1);totb=unique(b+1,b+totb+1)-b-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+totb+1,a[i])-b;
	for(int i=1;i<=q;i++)p[i].x=lower_bound(b+1,b+totb+1,p[i].x)-b;
	for(int i=1;i<=n;i++)s[a[i]].insert(i),val[a[i]]++;
	for(int i=1;i<=totb;i++)if(val[i])L[i]=*s[i].begin(),R[i]=*s[i].rbegin();
	for(int i=1;i<=totb;i++)if(val[i])T.modify(1,1,n,L[i],R[i]-1,1),T.insert(1,1,n,L[i],val[i]);
	printf("%d\\n",n-T.query());
	for(int i=1;i<=q;i++)
		int u=a[p[i].i],v=p[i].x;s[u].erase(p[i].i);
		if(val[u])T.insert(1,1,n,L[u],0);val[u]--;
		if(L[u]==p[i].i||R[u]==p[i].i)
			if(val[u]>=0)T.modify(1,1,n,L[u],R[u]-1,-1);
			if(val[u])L[u]=*s[u].begin(),R[u]=*s[u].rbegin(),
				T.modify(1,1,n,L[u],R[u]-1,1);
		
		if(val[u])T.insert(1,1,n,L[u],val[u]);
		if(val[v])T.insert(1,1,n,L[v],0); 
		s[v].insert(p[i].i);val[v]++;
		if(val[v]==1||L[v]>p[i].i||R[v]<p[i].i)
			if(val[v]>1)T.modify(1,1,n,L[v],R[v]-1,-1);
			if(val[v])L[v]=*s[v].begin(),R[v]=*s[v].rbegin(),
				T.modify(1,1,n,L[v],R[v]-1,1);
		
		if(val[v])T.insert(1,1,n,L[v],val[v]);
		printf("%d\\n",n-T.query());a[p[i].i]=v;
	
	return 0;

谢谢!!!

以上是关于[海军国际项目办公室]羽未的主要内容,如果未能解决你的问题,请参考以下文章

[海军国际项目办公室]打拳

[海军国际项目办公室]石子游戏

[海军国际项目办公室]游戏

[海军国际项目办公室]假人

[海军国际项目办公室]快递

[海军国际项目办公室]生之花