首页 > 其他分享 >【杂题乱写】6 月多校字符串专题训练

【杂题乱写】6 月多校字符串专题训练

时间:2023-06-27 20:11:33浏览次数:53  
标签:dep get 乱写 多校 mid int fa maxn 杂题

A CodeForces-547E Mike and Friends *2800

肯定要建广义 SAM。

在每个 \(cur\) 打一个标记,没有区间限制就在对应节点上查一下后缀树子树标记总数,有区间限制线段树合并维护标记。

点击查看代码
int n,q;
char s[maxn];
int mark[maxn];

struct SegmentTree{
#define mid ((l+r)>>1)
    int ch[maxn*40][2],tot;
    int siz[maxn*40];
    void insert(int &pos,int l,int r,int p){
        if(!pos) pos=++tot;
        ++siz[pos];
        if(l==r) return;
        if(p<=mid) insert(ch[pos][0],l,mid,p);
        else insert(ch[pos][1],mid+1,r,p);
    }
    int merge(int x,int y,int l,int r){
        if(!x||!y) return x+y;
        int pos=++tot;
        siz[pos]=siz[x]+siz[y];
        if(l==r) return pos;
        ch[pos][0]=merge(ch[x][0],ch[y][0],l,mid);
        ch[pos][1]=merge(ch[x][1],ch[y][1],mid+1,r);
        return pos;
    }
    int query(int pos,int l,int r,int pl,int pr){
        if(pl<=l&&r<=pr) return siz[pos];
        int res=0;
        if(ch[pos][0]&&pl<=mid) res+=query(ch[pos][0],l,mid,pl,pr);
        if(ch[pos][1]&&pr>mid) res+=query(ch[pos][1],mid+1,r,pl,pr);
        return res;
    }
#undef mid
}S;

struct SuffixAutomaton{
    int ch[maxn<<1][26],tot;
    int len[maxn<<1],link[maxn<<1];
    int rt[maxn<<1];
    SuffixAutomaton(){
        tot=0;
        len[0]=0,link[0]=-1;
    }
    inline int extend(int last,int c,vector<int> ID){
        int cur=++tot;
        len[cur]=len[last]+1;
        for(int i:ID) S.insert(rt[cur],1,n,i);
        int p=last;
        while(p!=-1&&!ch[p][c]){
            ch[p][c]=cur;
            p=link[p];
        }
        if(p==-1) link[cur]=0;
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q]) link[cur]=q;
            else{
                int clone=++tot;
                len[clone]=len[p]+1,link[clone]=link[q];
                for(int i=0;i<26;++i) ch[clone][i]=ch[q][i];
                while(p!=-1&&ch[p][c]==q){
                    ch[p][c]=clone;
                    p=link[p];
                }
                link[cur]=link[q]=clone;
            }
        }
        return cur;
    }
    vector<int> E[maxn<<1];
    void dfs(int u){
        for(int v:E[u]){
            dfs(v);
            rt[u]=S.merge(rt[u],rt[v],1,n);
        }
    }
    void solve(){
        for(int i=1;i<=tot;++i){
            E[link[i]].push_back(i);
        }
        dfs(0);
        while(q--){
            int l=read(),r=read(),k=read();
            printf("%d\n",S.query(rt[mark[k]],1,n,l,r));
        }
    }
}SAM;

struct Trie{
    int tr[maxn][26],tot;
    int fa[maxn],last[maxn],C[maxn];
    vector<int> ID[maxn];
    inline void insert(int id){
        int len=strlen(s+1);
        int u=0;
        for(int i=1;i<=len;++i){
            int c=s[i]-'a';
            if(!tr[u][c]) tr[u][c]=++tot;
            fa[tr[u][c]]=u,C[tr[u][c]]=c;
            ID[tr[u][c]].push_back(id);
            u=tr[u][c];
        }
        mark[id]=u;
    }
    inline void build(){
        queue<int> q;
        for(int i=0;i<26;++i){
            if(tr[0][i]) q.push(tr[0][i]);
        }
        while(!q.empty()){
            int u=q.front();
            q.pop();
            last[u]=SAM.extend(last[fa[u]],C[u],ID[u]);
            for(int i=0;i<26;++i){
                if(tr[u][i]) q.push(tr[u][i]);
            }
        }
        for(int i=1;i<=n;++i) mark[i]=last[mark[i]];
    }
}T;

int main(){
    n=read(),q=read();
    for(int i=1;i<=n;++i){
        scanf("%s",s+1);
        T.insert(i);
    }
    T.build();
    SAM.solve();
    return 0;
}

B CodeForces-504E Misha and LCP on Tree

哈希,维护根到当前节点路径的正反哈希,询问二分 \(\mathrm{lcp}\),需要支持查询树上 \(k\) 级祖先,倍增常数比树剖大。

也有一个 \(\log\) 的做法,先暴跳重链确定两条路径失配的重链,再在上面二分,但是不好写,树剖两个 \(\log\) 可过。

点击查看代码
inline int q_pow(int A,int B,int P){
    int res=1;
    while(B){
        if(B&1) res=1ll*res*A%P;
        A=1ll*A*A%P;
        B>>=1;
    }
    return res;
}

int n,q;
char s[maxn];
int pw1[maxn],pw2[maxn];
int inv_pw1[maxn],inv_pw2[maxn];
struct Graph{
    struct edge{
        int to,nxt;
    }e[maxn<<1];
    int head[maxn],cnt;
    inline void add_edge(int u,int v){
        e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt;
        e[++cnt].to=u,e[cnt].nxt=head[v],head[v]=cnt;
    }
    int fa[maxn],dep[maxn],siz[maxn],son[maxn];
    int top[maxn],dfn[maxn],dfncnt,id[maxn];
    int preh1[maxn],preh2[maxn],sufh1[maxn],sufh2[maxn];
    void dfs1(int u,int f,int d){
        fa[u]=f,dep[u]=d,siz[u]=1;
        preh1[u]=(preh1[f]+1ll*s[u]*pw1[dep[u]]%mod1)%mod1;
        preh2[u]=(preh2[f]+1ll*s[u]*pw2[dep[u]]%mod2)%mod2;
        sufh1[u]=(1ll*sufh1[f]*base1%mod1+s[u])%mod1;
        sufh2[u]=(1ll*sufh2[f]*base2%mod2+s[u])%mod2;
        int maxson=-1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==f) continue;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[v]>maxson) maxson=siz[v],son[u]=v;
        }
    }
    void dfs2(int u,int t){
        top[u]=t,dfn[u]=++dfncnt,id[dfncnt]=u;
        if(!son[u]) return;
        dfs2(son[u],t);
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    inline int get_LCA(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            v=fa[top[v]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        return u;
    }
    inline int get_fa(int u,int d){
        int x=u;
        while(dep[top[x]]>dep[u]-d) x=fa[top[x]];
        return id[dfn[x]-(dep[x]-(dep[u]-d))];
    }
    inline int get_hash1(int u,int v,int d,int lca,int dis){
        if(u==lca){
            int w=get_fa(v,dis-d);
            return (sufh1[w]-1ll*sufh1[fa[u]]*pw1[dep[w]-dep[fa[u]]]%mod1+mod1)%mod1;
        }
        else if(v==lca){
            int w=get_fa(u,d-1);
            return 1ll*(preh1[u]-preh1[fa[w]]+mod1)%mod1*inv_pw1[dep[w]]%mod1;
        }
        else{
            int res=0;
            if(d<=dep[u]-dep[lca]+1){
                int w=get_fa(u,d-1);
                res=1ll*(preh1[u]-preh1[fa[w]]+mod1)%mod1*inv_pw1[dep[w]]%mod1;
            }
            else{
                res=1ll*(preh1[u]-preh1[fa[lca]]+mod1)%mod1*inv_pw1[dep[lca]]%mod1;
                d-=dep[u]-dep[lca]+1;
                int w=get_fa(v,dep[v]-dep[lca]-d);
                res=1ll*res*pw1[dep[w]-dep[lca]]%mod1;
                res=(res+(sufh1[w]-1ll*sufh1[lca]*pw1[dep[w]-dep[lca]]%mod1+mod1)%mod1)%mod1;
            }
            return res;
        }
    }
    inline int get_hash2(int u,int v,int d,int lca,int dis){
        if(u==lca){
            int w=get_fa(v,dis-d);
            return (sufh2[w]-1ll*sufh2[fa[u]]*pw2[dep[w]-dep[fa[u]]]%mod2+mod2)%mod2;
        }
        else if(v==lca){
            int w=get_fa(u,d-1);
            return 1ll*(preh2[u]-preh2[fa[w]]+mod2)%mod2*inv_pw2[dep[w]]%mod2;
        }
        else{
            int res=0;
            if(d<=dep[u]-dep[lca]+1){
                int w=get_fa(u,d-1);
                res=1ll*(preh2[u]-preh2[fa[w]]+mod2)%mod2*inv_pw2[dep[w]]%mod2;
            }
            else{
                res=1ll*(preh2[u]-preh2[fa[lca]]+mod2)%mod2*inv_pw2[dep[lca]]%mod2;
                d-=dep[u]-dep[lca]+1;
                int w=get_fa(v,dep[v]-dep[lca]-d);
                res=1ll*res*pw2[dep[w]-dep[lca]]%mod2;
                res=(res+(sufh2[w]-1ll*sufh2[lca]*pw2[dep[w]-dep[lca]]%mod2+mod2)%mod2)%mod2;
            }
            return res;
        }
    }
    inline void solve(){
        while(q--){
            int a=read(),b=read(),c=read(),d=read();
            int lca1=get_LCA(a,b),lca2=get_LCA(c,d);
            int dis1=dep[a]+dep[b]-2*dep[lca1]+1,dis2=dep[c]+dep[d]-2*dep[lca2]+1;
            int l=1,r=min(dis1,dis2),ans=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(get_hash1(a,b,mid,lca1,dis1)==get_hash1(c,d,mid,lca2,dis2)&&get_hash2(a,b,mid,lca1,dis1)==get_hash2(c,d,mid,lca2,dis2)) ans=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d\n",ans);
        }
    }
}G;

int main(){
    n=read();
    pw1[0]=1,pw2[0]=1;
    for(int i=1;i<=n;++i) pw1[i]=1ll*pw1[i-1]*base1%mod1,pw2[i]=1ll*pw2[i-1]*base2%mod2;
    inv_pw1[n]=q_pow(pw1[n],mod1-2,mod1),inv_pw2[n]=q_pow(pw2[n],mod2-2,mod2);
    for(int i=n-1;i>=0;--i) inv_pw1[i]=1ll*inv_pw1[i+1]*base1%mod1,inv_pw2[i]=1ll*inv_pw2[i+1]*base2%mod2;
    scanf("%s",s+1);
    for(int i=1;i<n;++i){
        int u=read(),v=read();
        G.add_edge(u,v);
    }
    G.dfs1(1,0,0);
    G.dfs2(1,1);
    q=read();
    G.solve();
    return 0;
}

标签:dep,get,乱写,多校,mid,int,fa,maxn,杂题
From: https://www.cnblogs.com/SoyTony/p/Multiple_School_String_Training_Problems_in_June.html

相关文章

  • 【考后总结】6 月西安多校模拟赛 5
    6.24冲刺国赛模拟24T2简单图论题原题:Gym-104053CCustomsControls2构造题。这个限制可以进一步加强到对于每个节点\(u\),\(1\tou\)的路径权值都相等,定义为\(d_u\)。于是对\(u\)连边的两个节点的\(d\)一定相等,进而可以把所有相等的缩到一起,且这些点直接不能连边(点......
  • 【考后总结】6 月西安多校模拟赛 4
    6.21冲刺国赛模拟22T1跳跃不妨看作两只青蛙从相同起点出发且跳跃次数相同,设\(f_{i,j,k}\)为两只青蛙分别在\(i,j\)位置,且相差步数\(k\)。由于需要记录相邻位置对答案贡献,我们在要求必须严格按照升序对处理状态,也就是必须保证当前跳跃的一只青蛙落点在另一只青蛙更前面,且......
  • 【杂题乱写】6 月西安多校 DP 专题训练
    这也太难了!这也太难了!这也太难了!AUOJ-607UR#20跳蚤电话加点操作太抽象,改成删点,每次可以删一个叶子,或者删一个只有一个父亲和一个儿子的节点。算方案还带顺序,子树间再算多重集组合数不方便,不如直接算任意顺序删点最后合法删完的概率。设\(f_u\)为按任意顺序删点删完\(u\)......
  • 6.19 杂题
    【山东省选集训2023】T1.树染色有多少种选出\(\{(u_1,v_1),(u_2,v_2),...,(u_m,v_m)\}\)的方法,使得:任意\(u_i\)是\(v_i\)祖先;\(u_1=1\);对于任意\(i\ge2\),存在\(j<i\)使得\(u_i\)在\(u_i\tov_i\)的路径上;所有边被至少一条路径\(u_i\tov_i\)覆盖。对每......
  • 杂题3
    \(\text{CF547DMikeandFish}\)对于横坐标相同的点两两连边,剩下一个点不管,纵坐标同理这样形成的图是二分图,因为一个点只会在横轴上连出一条边,纵轴上连出一条边。最后黑白染色即可\(\text{CF547EMikeandFriends}\)差分询问,考虑每个字符串对询问的贡献于是建出ACAM,顺序处......
  • transform (牛客多校) (双指针+二分+ 中位数妙用+前缀和相减维护)
    题目大意:n个商店在一条直线上, 有一个xi然后有ai个商品你可以把商店的物品移动到另一个商店,代价为:abs(xi-xj)在代价不超过T的情况下你可以选择一个商店来让其他商店的物品都移到这个商店,问最多移动多少个物品  思路:双指针维护一个最大的区间,因......
  • 【考后总结】6 月西安多校模拟赛 3
    6.17冲刺国赛模拟20T1树染色容易发现每种方案都可以变成没有交边的链剖分,在此基础上的方案数是每个链顶的深度,考虑DP。直接DP大致是维护\(\prod(\proda+\prodb)\timesdep_{top}\),发现这个东西非常不好转移,转移时需要枚举叶子,复杂度不优秀。改为设\(f_{i,0/1}\)表......
  • farm (牛客多校) (二维树状+数学式子优化+rand()去除特殊情况)
    题目大意:给出一个n*m的田地矩阵,每个格子上种着一种植物。给格子施肥t次,每一次给出五个数字,x1,y1,x2,y2,k,要施肥的区域坐标和要施的肥料种类。如果植物和施肥种类不匹配,植物会死亡。问最终会死多少个植物。 思路:判断一个植物死不死, 判断植物种类*施肥次数==施肥种类总和某......
  • 6月CF杂题
    已经18号了捏。EducationalCodeforcesRound150(RatedforDiv.2)E.FilltheMatrix比较傻逼,但是是E,所以写一下。显然最优是横着填一段形如\(x,x+1,x+2\ldots\)的数,那么如果一段长度为\(l\)则贡献为\(l-1\),所以我们要尽量填进长的段里。现在问题就变成了维护每......
  • 6月CWOI杂题
    C0253【0617C组】模拟测试军训归来的第一场模拟赛,小寄。C【0601C组】树好神奇的题目。直径这个东西没什么能入手的性质,我们先考虑进行一些转化。对于直径,我们去找它的中心点。中心点可能在边上,于是把边拆开,比如边\((u,v)\)拆成\((u,x)(x,v)\),这样就有了\(2n-1\)个点......