• CF1437G Death DBMS


    Pro:
    https://www.luogu.com.cn/problem/CF1437G
    给定一个大小为n的字符串集合,每个字符串有一个初始为0的权值
    支持以下q次操作
    1.把第(x)个字符串的权值改为(k)
    2.给定一个字符串s,求出字符串集合中所有在s中出现过的字符串的权值的最大值

    Sol:
    显然考虑AC自动机+树链剖分

    #include<bits/stdc++.h>
    #define N 1500000
    #define db double
    #define ll long long
    #define ldb long double
    #define ull unsigned long long
    using namespace std;
    const int h=3,ki=149,mo=998244353;
    inline int inc(int x,int k){x+=k;return x>=mo?x-mo:x;}
    inline int dec(int x,int k){x-=k;return x<0?x+mo:x;}
    inline int read()
    {
    	char ch=0;
    	int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    	return x*flag;
    }
    inline void write(int x)
    {
    	if(!x)return (void)putchar(48);
    	if(x<0)putchar(45),x=-x;
    	int len=0,p[20];
    	while(x)p[++len]=x%10,x/=10;
    	for(int i=len;i>=1;i--)putchar(p[i]+48);
    }
    const db eps=1e-7,inf=1e9+7,pi=acos(-1);
    inline db Read(){db x;scanf("%lf",&x);return x;}
    inline void Write(db x){printf("%lf",x);}
    char s[N];
    int rt=1,size=1,f[N],po[N],nxt[N][26];
    void insert(int id)
    {
    	int n=strlen(s),x=rt;
    	for(int i=0;i<n;i++)
    	{
    		int k=s[i]-'a';
    		if(!nxt[x][k])nxt[x][k]=++size;
    		x=nxt[x][k];
    	}
    	po[id]=x;
    }
    queue<int>q;
    void build()
    {
    	q.push(rt);
    	for(int i=0;i<26;i++)nxt[0][i]=rt;
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		for(int i=0;i<26;i++)
    		if(nxt[x][i])f[nxt[x][i]]=nxt[f[x]][i],q.push(nxt[x][i]);
    		else nxt[x][i]=nxt[f[x]][i];
    	}
    }
    struct edge{int to,nxt;}e[N*2];
    int num,head[N];
    inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
    int times,p[N],id[N],fa[N],sz[N],dep[N],son[N],top[N];
    void dfs1(int x,int t)
    {
    	sz[x]=1;dep[x]=t;
    	for(int i=head[x];i!=-1;i=e[i].nxt)
    	{
    		int to=e[i].to;
    		if(dep[to])continue;
    		dfs1(to,t+1);
    		fa[to]=x;sz[x]+=sz[to];
    		if(sz[son[x]]<sz[to])son[x]=to;
    	}
    }
    void dfs2(int x,int tp)
    {
    	p[id[x]=++times]=x;top[x]=tp;
    	if(son[x])dfs2(son[x],tp);
    	for(int i=head[x];i!=-1;i=e[i].nxt)
    	{
    		int to=e[i].to;
    		if(top[to])continue;
    		dfs2(to,to);
    	}
    }
    struct Segment_Tree
    {
    	#define lson o<<1
    	#define rson o<<1|1
    	#define mid ((l+r)>>1)
    	int maxv[N*4];
    	inline void pushup(int o){maxv[o]=max(maxv[lson],maxv[rson]);};
    	void build(){memset(maxv,-1,sizeof(maxv));}
    	void optset(int o,int l,int r,int q,int k)
    	{
    		if(l==r)return (void)(maxv[o]=k);
    		if(q<=mid)optset(lson,l,mid,q,k);
    		else optset(rson,mid+1,r,q,k);
    		pushup(o);
    	}
    	int query(int o,int l,int r,int ql,int qr)
    	{
    		if(ql<=l&&r<=qr)return maxv[o];
    		int ans=-1;
    		if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
    		if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr));
    		return ans;
    	}
    }T;
    int query(int x)
    {
    	int ans=-1;
    	while(x!=1)ans=max(ans,T.query(1,1,size,id[top[x]],id[x])),x=fa[top[x]];
    	return ans;
    }
    int w[N];
    multiset<int>S[N];
    int main()
    {
    	int n=read(),qnum=read();
    	for(int i=1;i<=n;i++)scanf("%s",s),insert(i);build();
    	num=-1;memset(head,-1,sizeof(head));
    	for(int i=2;i<=size;i++)add(f[i],i);
    	fa[1]=1;dfs1(1,1);dfs2(1,1);T.build();
    	for(int i=1;i<=n;i++){int t=po[i];S[t].insert(0);T.optset(1,1,size,id[t],0);}
    	for(int o=1;o<=qnum;o++)
    	{
    		int flag=read();
    		if(flag==1)
    		{
    			int x=read(),k=read(),t=po[x];
    			S[t].erase(S[t].find(w[x]));S[t].insert(k);w[x]=k;
    			T.optset(1,1,size,id[t],*S[t].rbegin());
    		}
    		if(flag==2)
    		{
    			scanf("%s",s);
    			int len=strlen(s),ans=-1;
    			for(int i=0,x=1;i<len;i++)x=nxt[x][s[i]-'a'],ans=max(ans,query(x));
    			write(ans);putchar('
    ');
    		}
    	}
    	return 0;
    } 
    

    但是我们不妨考虑一下怎么用SAM来做这个题
    一样是考虑树剖维护
    但是,可能会出现这种情况
    原串abcd
    询问bcd
    结果abcd和bcd在一个节点
    导致查询错误
    这个的话
    两个解决办法
    一种是把询问的字符串也全部加到sam里面去
    使它们强行断开
    另一种方法可以考虑每个节点单独开一个一长度为下标的动态开点线段树
    里面存贮长度为i的最大权值
    由于相同长度的也可能有多个串
    所以叶子节点要用set来维护
    。。。。
    然后胡乱写上个200行就好了

    #include<bits/stdc++.h>
    #define N 1100000
    #define M 6600000
    #define db double
    #define ll long long
    #define ldb long double
    #define ull unsigned long long
    using namespace std;
    const int h=3,ki=149,mo=998244353;
    inline int inc(int x,int k){x+=k;return x>=mo?x-mo:x;}
    inline int dec(int x,int k){x-=k;return x<0?x+mo:x;}
    inline int read()
    {
    	char ch=0;
    	int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    	return x*flag;
    }
    inline void write(int x)
    {
    	if(!x)return (void)putchar(48);
    	if(x<0)putchar(45),x=-x;
    	int len=0,p[20];
    	while(x)p[++len]=x%10,x/=10;
    	for(int i=len;i>=1;i--)putchar(p[i]+48);
    }
    const db eps=1e-7,inf=1e9+7,pi=acos(-1);
    inline db Read(){db x;scanf("%lf",&x);return x;}
    inline void Write(db x){printf("%lf",x);}
    char ch[N];
    int root=1,size=1,last=1;
    struct node{int pos,len,lnk,nxt[27];}s[N];
    void build(int k)
    {
        int cur=++size,p=last;last=cur;
        s[cur].pos=s[p].len;s[cur].len=s[p].len+1;
        while(p&&!s[p].nxt[k])s[p].nxt[k]=cur,p=s[p].lnk;
        if(!p){s[cur].lnk=root;return;}
        int q=s[p].nxt[k];
        if(s[p].len+1==s[q].len)s[cur].lnk=q;
        else
        {
            int clone=++size;
            s[clone]=s[q];s[clone].len=s[p].len+1;
            while(p&&s[p].nxt[k]==q)s[p].nxt[k]=clone,p=s[p].lnk;
            s[q].lnk=s[cur].lnk=clone;
        }
    }
    struct edge{int to,nxt;}e[N*2];
    int num,head[N];
    inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
    int times,p[N],po[N],fa[N],id[N],sz[N],dep[N],top[N],son[N];
    void dfs1(int x,int t)
    {
    	sz[x]=1;dep[x]=t;
    	for(int i=head[x];i!=-1;i=e[i].nxt)
    	{
    		int to=e[i].to;
    		if(dep[to])continue;
    		dfs1(to,t+1);
    		fa[to]=x;sz[x]+=sz[to];
    		if(sz[son[x]]<sz[to])son[x]=to;
    	}
    }
    void dfs2(int x,int tp)
    {
    	p[++times]=x;id[x]=times;top[x]=tp;
    	if(son[x])dfs2(son[x],tp);
    	for(int i=head[x];i!=-1;i=e[i].nxt)
    	{
    		int to=e[i].to;
    		if(top[to])continue;
    		dfs2(to,to);
    	}
    }
    struct Segment_Tree
    {
    	#define lson o<<1
    	#define rson o<<1|1
    	#define mid ((l+r)>>1)
    	int maxv[N*4];
    	void build(){memset(maxv,-1,sizeof(maxv));}
    	void optset(int o,int l,int r,int q,int k)
    	{
    		if(l==r)return (void)(maxv[o]=k);
    		if(q<=mid)optset(lson,l,mid,q,k);
    		else optset(rson,mid+1,r,q,k);
    		maxv[o]=max(maxv[lson],maxv[rson]);
    	}
    	int query(int o,int l,int r,int ql,int qr)
    	{
    		if(ql<=l&&r<=qr)return maxv[o];
    		int ans=-1;
    		if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
    		if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr));
    		return ans;
    	}
    	#undef lson
    	#undef rson
    	#undef mid
    }T;
    int query(int x,int y)
    {
    	if(!x)return -1;
    	int ans=-1;
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		ans=max(ans,T.query(1,1,size,id[top[x]],id[x]));
    		x=fa[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	ans=max(ans,T.query(1,1,size,id[x],id[y]));
    	return ans;
    }
    int f[N],rt[N],length[N];
    multiset<int>S[N];
    multiset<int>::iterator it;
    struct Segment_Tree_
    {
    	#define lson lc[o]
    	#define rson rc[o]
    	#define mid ((l+r)>>1)
    	multiset<int>g[M];
    	int size,lc[M],rc[M],maxv[M];
    	void optset(int &o,int l,int r,int q,int x,int y)
    	{
    		if(!o)o=++size;
    		if(l==r)
    		{
    			if(x!=-1)g[o].erase(g[o].find(x));
    			g[o].insert(y);maxv[o]=*g[o].rbegin();
    			return;
    		}
    		if(q<=mid)optset(lson,l,mid,q,x,y);
    		else optset(rson,mid+1,r,q,x,y);
    		maxv[o]=-1;
    		if(lson)maxv[o]=max(maxv[o],maxv[lson]);
    		if(rson)maxv[o]=max(maxv[o],maxv[rson]);
    	}
    	int query(int o,int l,int r,int ql,int qr)
    	{
    		if(!o)return -1;
    		if(ql<=l&&r<=qr)return maxv[o];
    		int ans=-1;
    		if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
    		if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr)); 
    		return ans;
    	}
    }F;
    int sss,qwq[N];
    int main()
    {
    	int cnt=read(),qnum=read(),maxn=0;
    	for(int o=1;o<=cnt;o++)
    	{
    		scanf("%s",ch);
    		int len=strlen(ch);
    		for(int i=0;i<len;i++)build(ch[i]-'a'),qwq[++sss]=ch[i]-'a';
    		build(26);
    		
    		int x=1;
    		length[o]=len;
    		maxn=max(maxn,len);
    	}
    	for(int o=1,t=0;o<=cnt;o++)
    	{
    		int x=1;
    		for(int i=1;i<=length[o];i++)x=s[x].nxt[qwq[++t]];
    		po[o]=x;
    	}
    	num=-1;memset(head,-1,sizeof(head));
    	for(int i=2;i<=size;i++)add(s[i].lnk,i);
    	
    	dfs1(1,1);dfs2(1,1);T.build();
    	for(int i=1;i<=cnt;i++)
    	{
    		int t=po[i];
    		S[t].insert(0);
    		F.optset(rt[t],1,maxn,length[i],-1,0);
    		T.optset(1,1,size,id[t],0);
    	}
    	int ttt=0;
    	for(int o=1;o<=qnum;o++)
    	{
    		int flag=read();
    		if(flag==1)
    		{
    			int x=read(),k=read(),t=po[x];
    			it=S[t].find(f[x]);
    			S[t].erase(it);
    			S[t].insert(k); 
    			T.optset(1,1,size,id[t],*S[t].rbegin());
    			F.optset(rt[t],1,maxn,length[x],f[x],k);
    			f[x]=k;
    		}
    		if(flag==2)
    		{
    			scanf("%s",ch);
    			int ans=-1,len=strlen(ch);
    			for(int i=0,x=1,tot=0;i<len;i++)
    			{
    				int k=ch[i]-'a';
    				while(x!=1&&!s[x].nxt[k])x=s[x].lnk,tot=s[x].len;
    				if(s[x].nxt[k])x=s[x].nxt[k],tot++;
    				ans=max(ans,query(s[x].lnk,1));
    				if(x!=1)ans=max(ans,F.query(rt[x],1,maxn,1,tot));
    			}
    			write(ans);putchar('
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    idea最新注册码
    pycharm中可以运行脚本(只在控制台运行,Debugger不运行,设置的断点没用)但是不能debug脚本
    VSCode 云同步扩展设置 Settings Sync 插件
    gist.github.com 无法访问解决办法,亲测永远有效!
    C# HttpWebRequest httpclient
    C# 图片处理
    powerdesigner逆向工程生成PDM时的列注释
    Ocelot网关治理
    Consul服务注册与发现
    CentOS 使用DVD1_DVD2作为本地离线的更新源
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/13892764.html
Copyright © 2020-2023  润新知