[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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值