錄取查詢

zhengchenxi發表於2024-07-28

這道題賽時是想出來了,但是線段樹出鍋了,只得了20分。
首先根據題目我們可以得出,一個序列要是為T的子串,就必須滿足以下三個條件。

1.該序列單調不降。如 ba肯定是不合法的。
2.該序列除去開頭和結尾的字母,其他字母的數量必須為整個序列全部的該字母數量。
如 abbcba 選擇 abbc a和c不用管,序列中只出現了一次b,而整個序列有2個b,故所選序列是不合法的。

3.在滿足單調不降的條件下,相鄰兩個字母的之間不能出現還有字母按字典序排列位於他倆之間。
如 acb 選取ac這個序列,很明顯是滿足前兩個條件,但它是不合法的。

好,明白這些,我們再想如何用線段樹來維護,關於單調不降,我們可以想到之前所做的山海經,我們可以維護一個左邊界和右邊界,再維護一個vis標記,表示該區間是否合法。
只有在滿足左區間和右區間同時合法並且左區間的有邊界要小於右區間的左邊界時才合法(這算是最難維護的一點)。
剩下兩個都比較好說,直接遍歷一遍26個字母即可。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;

const int N=3e5+100;
int n,q;
char s[N];
int cnt[N];
#define lson (rt<<1)
#define rson (rt<<1|1)
struct lmy
{
	int l,r;
	int vis;
	int ls,rs;
	int cnt[30];
}tr[N<<2];

void pushup(int rt)
{
	for(int i=0;i<=26;i++) tr[rt].cnt[i]=tr[lson].cnt[i]+tr[rson].cnt[i];
	if(tr[lson].rs<=tr[rson].ls&&tr[lson].vis&&tr[rson].vis) tr[rt].vis=1;
	else tr[rt].vis=0;
	tr[rt].ls=tr[lson].ls; tr[rt].rs=tr[rson].rs;
}

void build(int rt,int l,int r)
{
	tr[rt].l=l;
	tr[rt].r=r;
	if(l==r)
	{
		tr[rt].cnt[s[l]-'a']++;
		tr[rt].ls=tr[rt].rs=s[l]-'a';
		tr[rt].vis=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(lson,l,mid); build(rson,mid+1,r);
	pushup(rt);
}

void update(int rt,int x,char ch)
{
	if(tr[rt].l==tr[rt].r)
	{
		tr[rt].cnt[s[x]-'a']--;
		s[x]=ch;
		tr[rt].cnt[s[x]-'a']++;
		
		tr[rt].ls=tr[rt].rs=s[x]-'a';
		return ;
	}
	int mid=(tr[rt].l+tr[rt].r)>>1;
	if(x<=mid) update(lson,x,ch);
	else update(rson,x,ch);
	pushup(rt);
}
lmy query(int rt,int l,int r)
{
	if(l<=tr[rt].l&&tr[rt].r<=r)
	{
		return tr[rt];
	}
	int mid=(tr[rt].l+tr[rt].r)>>1;
	lmy a,b,c;
	if(l<=mid&&r<=mid) return a=query(lson,l,r);
	if(r>mid&&l>mid) return b=query(rson,l,r);
	if(l<=mid&&r>mid)
	{
		a=query(lson,l,r);
		b=query(rson,l,r); 
		if(a.rs<=b.ls&&a.vis&&b.vis) c.vis=1;
		else c.vis=0;
		for(int i=0;i<=26;i++) 
		{
			c.cnt[i]=a.cnt[i]+b.cnt[i];
		}
		c.rs=b.rs;c.ls=a.ls;
		return c;	
	}
	
}

int main()
{
//	freopen("in.in","r",stdin);
//	freopen("0.out","w",stdout);
	scanf("%d",&n);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
	{
		cnt[s[i]-'a']++;
	}
	build(1,1,n);
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			int x;
			char ch;
			scanf("%d %c",&x,&ch);
			cnt[s[x]-'a']--;
			update(1,x,ch);
			cnt[s[x]-'a']++;
		}
		else
		{
			int l,r;
			scanf("%d%d",&l,&r);
			lmy a=query(1,l,r);
			int flag=a.vis;
			int i=0;
			int last=26;
			while(i<=26)
			{
				if(a.cnt[i])
				{
					for(int j=last+1;j<i;j++)
					{
						if(cnt[j]!=0) flag=0;
					}
					last=i;
					if(i==s[l]-'a'||i==s[r]-'a')
					{
						i++;
						continue;
					} 
					else if(cnt[i]!=a.cnt[i]) 
					{
						flag=0;
					} 
				}
				i++;
			}
			if(flag) printf("Yes\n");
			else printf("No\n");
		}
	}
}

相關文章