题目描述
有一棵树,每条边上面都有一个字母。每个点还有一个特征值(a_i)。
定义一个节点(i)对应的字符串为从这个点到根的路径上所有边按顺序拼接而成的字符串(s_i)。
有(m)次操作:
- (0~u~l~r):询问有多少个字符串(s_i)满足(lcp(s_i,s_u)geq l)且(a_ileq r)
- (1~f~a~c):新增一个点,父亲为(f),到父亲的边上的字符为(c)。
强制在线。
(n,mleq 40000)
题解
因为要加新的点而且要强制在线,所以只能用后缀平衡树了。
然后就会发现这是一道非常水的题了。
维护后缀平衡树,每个点再维护关键字为这个区间内每个点的特征值的一棵平衡树,也就是树套树。
后缀平衡树可以做到(O(1))比较大小,但是这题不需要。
(其实(O(1))求上面那个东西会跑的很快,但是我很懒。)
时间复杂度:(O((n+m)log^2 (n+m)))
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
#include<iostream>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
s=c-'0';
while((c=getchar())>='0'&&c<='9')
s=s*10+c-'0';
return s;
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int id(char c)
{
switch (c)
{
case 'A':return 1;
case 'C':return 2;
case 'G':return 3;
case 'T':return 4;
}
return 0;
}
namespace mempool
{
int a[2000010];
int t;
void init()
{
t=2000000;
for(int i=1;i<=t;i++)
a[i]=i;
}
int get()
{
return a[t--];
}
void push(int x)
{
a[++t]=x;
}
}
const ll inf=0x7fffffffffffffffll;
const ull base=127;
ull pw[20];
int n,m;
int a[100010];
//ll hs[100010];
int f[100010][18];
int d[100010];
ull h[100010][18];
int lcp(int x,int y)
{
if(d[x]>d[y])
swap(x,y);
int s=0;
for(int i=16;i>=0;i--)
if((1<<i)<=d[x])
if(h[x][i]==h[y][i])
{
x=f[x][i];
y=f[y][i];
s+=1<<i;
}
return s;
}
int cmp(int x,int y)
{
for(int i=16;i>=0;i--)
if((1<<i)<=d[x]&&(1<<i)<=d[y])
if(h[x][i]==h[y][i])
{
x=f[x][i];
y=f[y][i];
}
return (h[x][0]!=h[y][0]?(h[x][0]<h[y][0]?1:-1):0);
}
namespace treap
{
struct node
{
int k;
int c[2],s;
int v;
int f;
int l,r;
};
node a[2000010];
int newnode()
{
int p=mempool::get();
a[p].k=rand();
a[p].v=a[p].c[0]=a[p].c[1]=a[p].s=a[p].f=a[p].l=a[p].r=0;
return p;
}
void mt(int p)
{
a[p].s=a[a[p].c[0]].s+a[a[p].c[1]].s+1;
a[p].r=(a[p].c[1]?a[a[p].c[1]].r:a[p].v);
a[p].l=(a[p].c[0]?a[a[p].c[0]].l:a[p].v);
}
int ins(int &p,int x,int f=0)
{
if(!p)
{
p=newnode();
a[p].v=a[p].l=a[p].r=x;
a[p].s=1;
a[p].f=f;
return p;
}
int y;
if(x<=a[p].v)
y=ins(a[p].c[0],x);
else
y=ins(a[p].c[1],x);
mt(p);
return y;
}
void rotate(int x)
{
int p=a[x].f;
int q=a[p].f;
int ps=(x==a[p].c[1]);
int qs=(p==a[q].c[1]);
int c=a[x].c[ps^1];
if(a[p].f)
a[q].c[qs]=x;
a[x].c[ps^1]=p;
a[p].c[ps]=c;
if(c)
a[c].f=p;
a[p].f=x;
a[x].f=q;
mt(p);
mt(x);
}
void insert(int &p,int x)
{
int y=ins(p,x);
while(a[y].f&&a[a[y].f].k>a[y].k)
rotate(y);
while(a[p].f)
p=a[p].f;
}
void del(int &p)
{
if(a[p].c[0])
del(a[p].c[0]);
if(a[p].c[1])
del(a[p].c[1]);
mempool::push(p);
p=0;
}
int query(int p,int v)
{
if(!p)
return 0;
if(a[p].l>v)
return 0;
if(a[p].r<=v)
return a[p].s;
if(a[p].v<=v)
return a[a[p].c[0]].s+1+query(a[p].c[1],v);
return query(a[p].c[0],v);
}
void dfs(int p,int f)
{
a[p].f=f;
if(a[p].c[0])
dfs(a[p].c[0],p);
if(a[p].c[1])
dfs(a[p].c[1],p);
mt(p);
}
int st[100010];
void build(int &p,int *e,int l,int r)
{
int top=0;
for(int i=l;i<=r;i++)
{
int x=newnode();
a[x].v=a[x].l=a[x].r=e[i];
a[x].s=1;
while(top&&a[x].k>a[st[top]].k)
{
a[x].c[0]=st[top];
mt(st[top]);
top--;
}
if(a[x].c[0])
a[a[x].c[0]].f=x;
if(top)
{
a[st[top]].c[1]=x;
a[x].f=st[top];
}
st[++top]=x;
}
p=st[1];
while(top)
{
if(top>1)
{
a[st[top-1]].c[1]=st[top];
a[st[top]].f=st[top-1];
}
mt(st[top]);
top--;
}
// dfs(p,0);
}
}
namespace sgt
{
const double alpha=0.75;
struct node
{
int l,r;
int ls,rs;
int x;
int rt;
int s;
};
node a[100010];
int rt;
int cnt;
int *rebuild;
void mt(int p)
{
a[p].s=a[a[p].ls].s+a[a[p].rs].s+1;
a[p].l=(a[p].ls?a[a[p].ls].l:a[p].x);
a[p].r=(a[p].rs?a[a[p].rs].r:a[p].x);
}
void ins(int &p,int x)
{
if(!p)
{
p=++cnt;
a[p].l=a[p].r=x;
a[p].ls=a[p].rs=0;
a[p].x=x;
a[p].rt=0;
a[p].s=1;
treap::insert(a[p].rt,::a[x]);
return;
}
treap::insert(a[p].rt,::a[x]);
if(cmp(x,a[p].x)==1)
{
ins(a[p].ls,x);
mt(p);
if(a[a[p].ls].s>a[p].s*alpha)
rebuild=&p;
}
else
{
ins(a[p].rs,x);
mt(p);
if(a[a[p].rs].s>a[p].s*alpha)
rebuild=&p;
}
}
int tot;
int c[100010];
int d[100010];
void dfs(int &x)
{
if(a[x].ls)
dfs(a[x].ls);
c[++tot]=x;
d[tot]=a[x].x;
if(a[x].rs)
dfs(a[x].rs);
treap::del(a[x].rt);
x=0;
}
int e[100010];
int f[100010];
void build(int &p,int l,int r)
{
if(l>r)
return;
int mid=(l+r)>>1;
p=c[mid];
a[p].x=d[mid];
// for(int i=l;i<=r;i++)
// treap::insert(a[p].rt,::a[d[i]]);
build(a[p].ls,l,mid-1);
build(a[p].rs,mid+1,r);
if(l==r)
e[l]=::a[d[l]];
else
{
int v=::a[d[mid]];
int i;
for(i=mid;i>l&&v<e[i-1];i--)
e[i]=e[i-1];
e[i]=v;
int l1=l,r1=mid+1;
int t1=l;
while(l1<=mid||r1<=r)
if(r1>r||(l1<=mid&&e[l1]<=e[r1]))
f[t1++]=e[l1++];
else
f[t1++]=e[r1++];
for(int i=l;i<=r;i++)
e[i]=f[i];
}
treap::build(a[p].rt,e,l,r);
mt(p);
}
void insert(int x)
{
rebuild=0;
ins(rt,x);
if(rebuild)
{
tot=0;
dfs(*rebuild);
build(*rebuild,1,tot);
}
}
int query(int p,int x,int l,int r)
{
if(!p)
return 0;
if(lcp(a[p].x,x)>=l)
{
if(lcp(a[p].l,x)>=l&&lcp(a[p].r,x)>=l)
return treap::query(a[p].rt,r);
return query(a[p].ls,x,l,r)+query(a[p].rs,x,l,r)+(::a[a[p].x]<=r?1:0);
}
int v=cmp(x,a[p].x);
int s=0;
if(v!=-1)
s+=query(a[p].ls,x,l,r);
if(v!=1)
s+=query(a[p].rs,x,l,r);
return s;
}
}
void add(int x,int y,int v)
{
h[x][0]=v;
f[x][0]=y;
d[x]=d[y]+1;
for(int i=1;i<=16;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
h[x][i]=h[x][i-1]*pw[i-1]+h[f[x][i-1]][i-1];
}
sgt::insert(x);
}
int query(int x,int l,int r)
{
return sgt::query(sgt::rt,x,l,r);
}
int main()
{
open("b");
srand(time(0));
mempool::init();
pw[0]=base;
for(int i=1;i<=17;i++)
pw[i]=pw[i-1]*pw[i-1];
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
d[1]=0;
d[0]=-1;
char c[2];
int x,y,l,r;
for(int i=2;i<=n;i++)
{
scanf("%d%d%s",&x,&y,c);
add(y,x,id(c[0]));
}
int last=1;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(!x)
{
scanf("%d%d%d",&x,&l,&r);
x^=last;
int ans=query(x,l,r);
if(!l&&a[1]<=r)
ans++;
printf("%d
",ans);
if(ans)
last=ans;
}
else
{
n++;
scanf("%d%d%s",&x,&a[n],c);
x^=last;
add(n,x,id(c[0]));
}
}
return 0;
}