zoukankan      html  css  js  c++  java
  • 洛谷P4482 [BJWC2018] Border 的四种求法

    询问等价于在 ([l,r)) 中找到最大的 (i) 满足 (lcs(i,r)geqslant i-l+1)。把问题放到 (Parent) 树上来考虑,设 (len)(i,r) 对应节点的 (lca) 的长度,条件变为 (i-len<l)

    考虑一种暴力,先线段树合并维护出每个节点的 ( ext{endpos}) 集合,然后枚举 (r) 对应节点的祖先,在祖先节点上线段树二分来更新答案,这里不会算进去 (r) 对应节点子树内的点,因为这些点显然不优。但对每个祖先都做的话,复杂度是无法接受的。

    考虑对 (Parent) 树进行重链剖分,只在到根的路径上的每个重链底部进行这个做法。重链上的其他祖先节点的贡献统一处理,将询问离线挂到对应的若干重链上,重链上的点暴力将轻儿子子树内的信息加到当前点的线段树里,因为轻儿子子树大小和为 (O(nlog n)),所以复杂度有保证。用线段树合并来实现前缀信息合并,同样是在线段树上二分查询。

    总复杂度为 (O(n log^2 n))

    #include<bits/stdc++.h>
    #define maxn 400010
    #define maxm 18000010
    #define inf 1000000000
    #define mid ((l+r)>>1)
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,q,las=1,tot=1;
    int ans[maxn],fa[maxn],len[maxn],ch[maxn][28],bel[maxn],siz[maxn],son[maxn],top[maxn];
    char s[maxn];
    struct edge
    {
        int to,nxt;
        edge(int a=0,int b=0)
        {
            to=a,nxt=b;
        }
    }e[maxn];
    int head[maxn],edge_cnt;
    void add(int from,int to)
    {
        e[++edge_cnt]=edge(to,head[from]),head[from]=edge_cnt;
    }
    struct node
    {
        int l,r,id;
        node(int a=0,int b=0,int c=0)
        {
            l=a,r=b,id=c;
        }
    };
    vector<node> ve[maxn];
    struct ST
    {
        int tot;
        int rt[maxn],ls[maxm],rs[maxm],mn[maxm];
        void modify(int l,int r,int pos,int v,int &cur)
        {
            if(!cur) mn[cur=++tot]=inf;
            mn[cur]=min(mn[cur],v);
            if(l==r) return;
            if(pos<=mid) modify(l,mid,pos,v,ls[cur]);
            else modify(mid+1,r,pos,v,rs[cur]);
        }
        int query(int L,int R,int l,int r,int v,int cur)
        {
            if(!cur||L>r||R<l||mn[cur]>=v) return 0;
            if(l==r) return l;
            int pos=0;
            if(pos=query(L,R,mid+1,r,v,rs[cur])) return pos;
            if(pos=query(L,R,l,mid,v,ls[cur])) return pos;
            return 0;
        }
        int merge(int x,int y)
        {
            if(!x||!y) return x+y;
            int p=++tot;
            mn[p]=min(mn[x],mn[y]);
            ls[p]=merge(ls[x],ls[y]),rs[p]=merge(rs[x],rs[y]);
            return p;
        }
    }T1,T2;
    void insert(int c,int id)
    {
        int p=las,np=las=++tot;
        len[np]=len[p]+1,bel[id]=np,T1.modify(1,n,id,id,T1.rt[np]),T2.modify(1,n,id,0,T2.rt[np]);
        while(p&&!ch[p][c]) ch[p][c]=np,p=fa[p];
        if(!p) fa[np]=1;
        else
        {
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else
            {
                int nq=++tot;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                len[nq]=len[p]+1,fa[nq]=fa[q],fa[q]=fa[np]=nq;
                while(ch[p][c]==q) ch[p][c]=nq,p=fa[p];
            }
        }
    }
    void dfs_son(int x)
    {
        siz[x]=1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            dfs_son(y),siz[x]+=siz[y],T1.rt[x]=T1.merge(T1.rt[x],T1.rt[y]);
            if(siz[y]>siz[son[x]]) son[x]=y;
        }
    }
    void dfs_chain(int x,int tp)
    {
        top[x]=tp;
        if(son[x]) dfs_chain(son[x],tp);
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(top[y]) continue;
            dfs_chain(y,y);
        }
    }
    void get(int l,int r,int x,int cur)
    {
        if(!cur) return;
        if(l==r)
        {
            T2.modify(1,n,l,l-len[x],T2.rt[x]);
            return;
        }
        get(l,mid,x,T1.ls[cur]),get(mid+1,r,x,T1.rs[cur]);
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=e[i].nxt) dfs(e[i].to);
        if(x!=top[x]) return;
        while(x)
        {
            for(int i=head[x];i;i=e[i].nxt)
                if(e[i].to!=son[x])
                    get(1,n,x,T1.rt[e[i].to]);
            for(int i=0;i<ve[x].size();++i)
            {
                int l=ve[x][i].l,r=ve[x][i].r,id=ve[x][i].id;
                ans[id]=max(ans[id],T2.query(l,r-1,1,n,l,T2.rt[x])-l+1);
            }
            T2.rt[son[x]]=T2.merge(T2.rt[son[x]],T2.rt[x]),x=son[x];
        }
    }
    int main()
    {
        scanf("%s",s+1),n=strlen(s+1),read(q);
        for(int i=1;i<=n;++i) insert(s[i]-'a',i);
        for(int i=2;i<=tot;++i) add(fa[i],i);
        dfs_son(1),dfs_chain(1,1);
        for(int i=1;i<=q;++i)
        {
            int l,r,x;
            read(l),read(r),x=bel[r];
            while(x)
            {
                ve[x].push_back(node(l,r,i));
                ans[i]=max(ans[i],T1.query(l,r-1,1,n,len[x]+l,T1.rt[x])-l+1),x=fa[top[x]];
            }
        }
        dfs(1);   
        for(int i=1;i<=q;++i) printf("%d
    ",max(ans[i],0));
        return 0;
    }
    
  • 相关阅读:
    PyTools包罗万象的python工具包
    手撕神经网络实验报告
    数组模拟队列 以及队列的复用(环形队列)
    Sentinel熔断降级
    二维数组与稀疏数组的转换dataStructures
    Sentine熔断降级进阶
    Centos7防火墙以及端口控制
    docker的安装以及使用命令
    ToDesk个人免费 极致流畅的远程协助软件
    typora+PicGo+gitee搭建免费的的床
  • 原文地址:https://www.cnblogs.com/lhm-/p/14453951.html
Copyright © 2011-2022 走看看