【XSY2773】基因 后缀平衡树 树套树

题目描述

  有一棵树,每条边上面都有一个字母。每个点还有一个特征值\(a_i\)

  定义一个节点\(i\)对应的字符串为从这个点到根的路径上所有边按顺序拼接而成的字符串\(s_i\)

  有\(m\)次操作:

  • \(0~u~l~r\):询问有多少个字符串\(s_i\)满足\(lcp(s_i,s_u)\geq l\)\(a_i\leq r\)
  • \(1~f~a~c\):新增一个点,父亲为\(f\),到父亲的边上的字符为\(c\)

  强制在线。

  \(n,m\leq 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\n",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;
}

转载于:https://www.cnblogs.com/ywwyww/p/8573561.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值