【HDU6345】子串查詢【字首和】【線段樹】
阿新 • • 發佈:2018-11-09
題目大意:
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6345
求給定串
到
的位置裡字典序最小的字串出現的次數。
思路:
字典序最小的串,肯定是一個字元啊。
可以用線段樹維護一下。時間複雜度
當然也可以用字首和。時間複雜度
程式碼:
線段樹:
#include <cstdio>
#include <cstring>
#include <iostream>
#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].c<tree[x*2+1].c)
{
tree[x].c=tree[x*2].c;
tree[x].sum=tree[x*2].sum;
}
else
{
tree[x].c=tree[x*2+1].c;
tree[x].sum=tree[x*2+1].sum;
}
return;
}
int find(int x,int l,int r)
{
if (tree[x].l==l&&tree[x].r==r)
return tree[x].sum*100+(int)(tree[x].c-'A');
//這裡用到了一些小技巧,本來要返回一個字元和出現次數的,但是我直接返回出現次數*100再加上字元的ASCII碼值-A的ASCII碼值
if (tree[x].l==tree[x].r)
return 0;
int mid=(tree[x].l+tree[x].r)/2;
if (r<=mid) return find(x*2,l,r);
if (l>mid) 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%100<b%100) return a;
if (a%100>b%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 <cstdio>
#include <iostream>
#include <cstring>
#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;
}