【HDU6345】子串查询【前缀和】【线段树】

题目大意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6345
求给定串 l l l r r r的位置里字典序最小的字串出现的次数。


思路:

字典序最小的串,肯定是一个字符啊。
可以用线段树维护一下。时间复杂度 O ( T q   l o g n ) O(Tq\ logn) O(Tq logn)
当然也可以用前缀和。时间复杂度 O ( t ( q + n ) ) O(t(q+n)) O(t(q+n))


代码:

线段树:

#include 
#include 
#include 
#define N 1000100
using namespace std;

int n,t,m;
char c[N];

struct node
{
	int l,r,sum;
	char c;
}tree[N*3];

void make(int x)  //建树
{
	if (tree[x].l==tree[x].r) 
	{
		tree[x].c=c[tree[x].l];
		tree[x].sum=1;
		return;
	}
	int mid=(tree[x].l+tree[x].r)/2;
	tree[x*2].l=tree[x].l;
	tree[x*2].r=mid;
	tree[x*2+1].l=mid+1;
	tree[x*2+1].r=tree[x].r;
	make(x*2);
	make(x*2+1);
	if (tree[x*2].c==tree[x*2+1].c)  //最小字符和出现次数更改
	{
		tree[x].c=tree[x*2].c;
		tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
	}
	else if (tree[x*2].cmid) return find(x*2+1,l,r);
	int a=find(x*2,l,mid);
	int b=find(x*2+1,mid+1,r);
	if (a%100b%100) return b;  //取出字符和ASCII码
	return (a/100+b/100)*100+a%100;  //更新
}

int main()
{
	scanf("%d",&t);
	int x,y;
	for (int q=1;q<=t;q++)
	{
		scanf("%d%d",&n,&m);
		cin>>c+1;
		tree[1].l=1;
		tree[1].r=n;
		make(1);
		printf("Case #%d:\n",q);
		while (m--)
		{
			scanf("%d%d",&x,&y);
			int a=find(1,x,y);
		    printf("%d\n",a/100);
		}
	}
	return 0;
}

前缀和:

#include 
#include 
#include 
#define N 1000100
using namespace std;

int s[N][30],t,n,m,l,r;
char c[N];

int main()
{
	scanf("%d",&t);
	for (int q=1;q<=t;q++)
	{
		memset(s,0,sizeof(s));
		scanf("%d%d",&n,&m);
		cin>>c+1;
		for (int i=1;i<=n;i++)
		 s[i][c[i]-'A'+1]++;
		for (int i=1;i<=n;i++)
		 for (int j=1;j<=26;j++)
		  s[i][j]+=s[i-1][j];
		printf("Case #%d:\n",q);
		while (m--)
		{
			scanf("%d%d",&l,&r);
			for (int i=1;i<=26;i++)
			 if (s[r][i]-s[l-1][i])
			 {
			 	printf("%d\n",s[r][i]-s[l-1][i]);
			 	break;
			 }
		}
	}
	return 0;
}

你可能感兴趣的:(线段树)