题解 CF589C Polycarp's Masterpiece
magic!科学的可持久化!
可持久化平衡树,他好吗?他不好!
考虑魔改可持久化线段树!
我们先对原序列建一棵线段树,支持求区间某字符出现次数。
然后我们要支持
每次 copy 是把后
众所周知线段树会把一个区间分成
所以,我们把要 copy 的区间分成子段,排成一个序列,然后在他们上面建树!
设序列长为
相信你看了图之后就会了!
一些实现细节:
线段树比较臃肿,换成非 leafy tree(相当于把线段树换成一棵完美的平衡树)会快些。
这个线段树不方便维护区间左右端点(你写了自然知道),所以不妨维护每个节点的
另外,维护
#include<bits/stdc++.h>
#define ll long long
using namespace std;
char s[105];
int cnt,ncnt;
struct seg
{
ll size;
int s[2];
ll cnt[26];
}t[1000005];
#define ls t[w].s[0]
#define rs t[w].s[1]
int nd[100005];
int build(int l,int r)
{
int w=++cnt,i,mid=l+r>>1;
t[w].size=r-l+1;
for(i=l;i<=r;i++)
t[w].cnt[s[i]-'a']++;
if(l<r)
ls=build(l,mid),
rs=build(mid+1,r);
return w;
}
void pushup(int w)
{
for(int i=0;i<26;i++)
t[w].cnt[i]=t[ls].cnt[i]+t[rs].cnt[i];
t[w].size=t[ls].size+t[rs].size;
}
void getp(int w,ll x)
{
if(t[w].size==1)
{
if(x) nd[++ncnt]=w;
}
else if(x>t[ls].size)
nd[++ncnt]=ls,getp(rs,x-t[ls].size);
else
getp(ls,x);
}
void getn(int w,ll x)
{
if(t[w].size==1)
{
if(x) nd[++ncnt]=w;
}
else if(x>t[rs].size)
getn(ls,x-t[rs].size),nd[++ncnt]=rs;
else
getn(rs,x);
}
int build2(int l,int r)
{
if(l==r) return nd[l];
int w=++cnt,mid=l+r>>1;
ls=build2(l,mid),
rs=build2(mid+1,r);
pushup(w);
return w;
}
ll ask(int w,ll x,int c)
{
if(t[w].size==1)
return x*t[w].cnt[c];
if(x>t[ls].size)
return ask(rs,x-t[ls].size,c)+t[ls].cnt[c];
return ask(ls,x,c);
}
int main()
{
int n,m,rt,k,ne;
ll len,l,r;
char c[3];
scanf("%s%d%d",s+1,&n,&m);
rt=build(1,len=strlen(s+1));
while(n--)
{
scanf("%d",&k);
if(len>1e18) continue;
k%=len;
ncnt=0;
getn(rt,k),getp(rt,len-k);
ne=++cnt;
t[ne].s[0]=rt,
t[ne].s[1]=build2(1,ncnt);
pushup(rt=ne);
len*=2;
}
while(m--)
{
scanf("%lld%lld%s",&l,&r,c);
printf("%lld\n",ask(rt,r,*c-'a')-ask(rt,l-1,*c-'a'));
}
}