「洛谷P7416」No Time to Dry P

image
image
\({Luogu~link}\)

分析:

一个显然思路:找出区间内颜色数量 \(ans\) 如果如 \(212\) 这样中间会断开的情况 就要继续涂
每个位置记录一个 \(las_i\) 表示左边第一个颜色相同的位置
对于新的点 找出 \(las_i\)\(i-1\) 的最小值 \(Min\)\(Min<a_i\) 说明从 \(las_{i}\)\(i\) 断开了 若断开 \(las_i=0\)
找这个最小值可以用\(st\)

对于 \([l,r]\)\(las_i<l\) 就要重新涂 用主席树维护

CODE:

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=2e5+5;
int n,T,a[N],las[N],root[N],id,st[N][30],pre[N];
struct SegmentTree{
	int l,r,cnt;
}tree[N*40];
void update(int &x,int las,int k,int l,int r,int p)
{
	x=++id;
	tree[x]=tree[las];
	if(l==r){
		tree[x].cnt+=k;
		return;
	} 
	int mid=(l+r)>>1;
	if(p<=mid) update(tree[x].l,tree[las].l,k,l,mid,p);
	else update(tree[x].r,tree[las].r,k,mid+1,r,p);
	tree[x].cnt=tree[tree[x].l].cnt+tree[tree[x].r].cnt;
}
int Min(int l,int r)
{
	int len=log2(r-l+1);
	return min(st[l][len],st[r-(1<<len)+1][len]);
}
int query(int x,int las,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tree[x].cnt-tree[las].cnt;
	int res=0;
	int mid=(l+r)>>1;
	if(L<=mid) res+=query(tree[x].l,tree[las].l,l,mid,L,R);
	if(mid<R) res+=query(tree[x].r,tree[las].r,mid+1,r,L,R);
	return res;
}
int main(){
	scanf("%d%d",&n,&T);
	for(register int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		st[i][0]=a[i];
	}
	for(register int j=1;j<=log2(n);j++)
		for(register int i=1;i+(1<<j)-1<=n;i++)
			st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
	for(register int i=1;i<=n;i++)
	{
		if(Min(pre[a[i]],i)<a[i])
			las[i]=0;
		else las[i]=pre[a[i]];
		pre[a[i]]=i;
	}	
	for(register int i=1;i<=n;i++)
	{
		las[i]++;
		update(root[i],root[i-1],1,1,n,las[i]);
	}
	while(T--)
	{
		int l,r,ans=0;
		scanf("%d%d",&l,&r);
		ans=query(root[r],root[l-1],1,n,1,l);
		printf("%d\n",ans);
	}
	return 0;
} 
posted @ 2022-01-20 09:33  EschatonRin  阅读(9)  评论(0)    收藏  举报