[LuoguU41039]PION后缀自动机 树链剖分

链接

刚开始看出题人题解都吓蒙掉了,还以为是什么难题,结果就一板子题

思路:对每一个文件名开一棵线段树,然后树剖即可

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int>pii;
template<typename T,typename U>inline char smin(T&x,const U&y){return x>y?x=y,1:0;}
template<typename T,typename U>inline char smax(T&x,const U&y){return x<y?x=y,1:0;}
int T;
struct hash_table{
    static const int S=1e6+5;
    int head[S],to[S],ne[S];
    inline int get(char *s){
        int u=0;while(*s)u=u*27+*s++-‘a‘+1;int p=u%S;
        for(int i=head[p];i;i=ne[i])if(to[i]==u)return i;
        to[++T]=u,ne[T]=head[p],head[p]=T;
        return T;
    }
}mp;
const int N=1e5+5,MT=5e5+5;
int n,m;
vector<int>g[N];
int fa[N],dep[N],top[N],in[N],son[N],siz[N],dfn;
inline void go1(int x){
    siz[x]=1;
    for(int y:g[x])if(y!=fa[x])
    dep[y]=dep[x]+1,fa[y]=x,go1(y),siz[x]+=siz[y],siz[y]>siz[son[x]]&&(son[x]=y);
}
inline void go2(int x,int anc){
    in[x]=++dfn,top[x]=anc;
    if(!son[x])return;go2(son[x],anc);
    for(int y:g[x])if(y!=fa[x]&&y!=son[x])go2(y,y);
}
inline int dis(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=dep[x]-dep[top[x]]+1;x=fa[top[x]];
    }
    return ans+abs(dep[x]-dep[y]);
}
int rt[MT],treecnt;
struct tree{int ls,rs,w;bool del;}t[MT*25];
inline void ins(int&o,int l,int r,int x){
    if(!o)o=++treecnt;++t[o].w;
    if(l==r)return;int mid=l+r>>1;
    x<=mid?ins(t[o].ls,l,mid,x):ins(t[o].rs,mid+1,r,x);
}
inline void pushdown(int o){
    if(t[o].del){
        if(t[o].ls)t[t[o].ls].w=0,t[t[o].ls].del=1;
        if(t[o].rs)t[t[o].rs].w=0,t[t[o].rs].del=1;
        t[o].del=0;
    }
}
inline int ask(int o,int l,int r,int x,int y){
    if(!o||x>r||y<l||x>y||t[o].del)return 0;
    if(x<=l&&r<=y)return t[o].w;pushdown(o);
    int mid=l+r>>1;
    return ask(t[o].ls,l,mid,x,y)+ask(t[o].rs,mid+1,r,x,y);
}
inline int update(int o,int l,int r,int x,int y){
    if(!o||x>y||t[o].del)return 0;
    if(x<=l&&r<=y){
        int res=t[o].w;t[o].w=0;t[o].del=1;return res;
    }
    int mid=l+r>>1,res=0;pushdown(o);
    if(x<=mid)res+=update(t[o].ls,l,mid,x,y);
    if(y>mid)res+=update(t[o].rs,mid+1,r,x,y);
    t[o].w=t[t[o].ls].w+t[t[o].rs].w;
    return res;
}
inline int ask(int o,int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=ask(o,1,n,in[top[x]],in[x]);x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return ans+ask(o,1,n,in[x],in[y]);
}
inline int update(int o,int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=update(o,1,n,in[top[x]],in[x]);x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return ans+update(o,1,n,in[x],in[y]);
}
int main(){
    scanf("%d%d",&n,&m);
    REP(i,2,n){
        #define pb push_back
        int x,y;scanf("%d%d",&x,&y);g[x].pb(y),g[y].pb(x);
    }
    go1(1),go2(1,1);
    static char s[10];
    REP(i,1,n){
        int t;scanf("%d",&t);
        while(t--){
            scanf("%s",s);
            ins(rt[mp.get(s)],1,n,in[i]);
        }
    }
    while(m--){
        scanf("%s",s);
        int x,y;
        if(s[0]==‘q‘){
            scanf("%s%d%d",s,&x,&y);
            if(s[1]==‘p‘)printf("%d\n",dis(x,y));
            else{
                scanf(" *.%s",s);printf("%d\n",ask(rt[mp.get(s)],x,y));
            }
        }else{
            scanf("%*s%d%d *.%s",&x,&y,s);
            printf("%d\n",update(rt[mp.get(s)],x,y));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/HolyK/p/9835849.html

时间: 2024-10-16 12:25:28

[LuoguU41039]PION后缀自动机 树链剖分的相关文章

【AC自动机+树链剖分】HDU 5566

离线做法 对给出的树作树剖 把每个询问区间先加入线段树的结点 后对线段树每个有询问的节点建立AC自动机 对每个节点单独询问 1 // #include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #include <queue> 5 #include <cstring> 6 #include <cctype> 7 #include <algorithm&

CF 504E Misha and LCP on Tree(树链剖分+后缀数组)

题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. 思路:树链剖分,记录每条链的串,正反都记,组成一个大串.记录每条链对应的串在大串中的位置.然后对大串求后缀数组.最后询问就是在一些链上的查询. 树链剖分总是那么优秀.. const int N=600005; int next[N],node[N],head[N],e; void add(int u

CF gym 100962D Deep Purple [后缀树,树链剖分,线段树]

Codeforces 思路 感觉这个离线的思路好神仙啊qwq 对于每个询问\([l,r]\)其实就是要求\(p_{max}\),使得\(lcs(s[1,p],s[1,r])>p-l\),也就是\(lcs(s[1,p],s[1,r])+l>p\). 首先把询问离线按\(r\)排序,然后从右往左扫,每次 处理之前已经被加进去的询问,看当前位置是否能被作为\(p\),然后把已经处理完毕的询问给删掉. 把当前询问塞进去. 建出反串的后缀树,那么不等式左边就是\(dep_{lca(p,r)}+l\).

树链剖分教程 &amp; bzoj 1036 [ZJOI2008] 树的统计 Count 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24669751 [原题] 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4465  Solved: 1858 [Submit][Status] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I