「洛谷P7416」No Time to Dry P
分析:
一个显然思路:找出区间内颜色数量 \(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;
}



浙公网安备 33010602011771号