• [NOI2018] 你的名字


    题目大意:给出一个串(S)(q)次询问每次询问字符串(T)不在(S[l,r])出现的本质不同的子串数目。

    0.68

    有条件(l=1,r=|S|)。考虑(SAM_T)上的parent树的结构特点,不难可以得出:若设(lim_i)(T[1,i])(S)中出现的最长后缀长度(在(SAM_S)上直接跑整个(T)就能预处理),(tar_x)为集合(right_x)中任一元素,答案可以表示为

    [sum_{xin SAM_T} |[0,lim_{tar_x}]cap[mxl_{prt_x}+1,mxl_x]| ]

    (其实画图想了好久。。)

    1.00

    将上一个做法中的预处理部分做出如下修改:若目标状态的right集合存在位于([l+len-1,r])中的元素则转移(len是已上一个后缀的lim值),否则挨个考虑时len-=1,当len=prt的mxl时转向prt节点。(对于len满足|对于len-1满足?)

    这样使用可持久化线段树+线段树合并求出right集合来做。


    感谢 QAQ

    恼惭做了60h。

    代码 :模板线段树合并求right集合

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    
    const int N=1e6+10; //faq
    
    namespace SGT {
    	int ch[N*30][2],cnt;
    	bool exi[N*30];
    	void insert(int&x,int l,int r,int p) {
    		exi[x=++cnt]=1;
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		if(p<=mid) insert(ch[x][0],l,mid,p);
    		else insert(ch[x][1],mid+1,r,p);
    	}
    	int merge(int x,int y,int l,int r) {
    		if(!x||!y) return x|y;
    		int nd=++cnt,mid=(l+r)>>1;
    		ch[nd][0]=merge(ch[x][0],ch[y][0],l,mid);
    		ch[nd][1]=merge(ch[x][1],ch[y][1],mid+1,r);
    		exi[nd]=exi[ch[nd][0]]|exi[ch[nd][1]];
    		return nd;
    	}
    	bool query(int x,int l,int r,int L,int R) {
    		//printf("[%d,%d,%d,%d,%d]
    ",x,l,r,L,R);
    		if(!x||R<L) return 0;
    		if(L<=l&&r<=R) return exi[x];
    		int mid=(l+r)>>1;
    		if(L<=mid&&query(ch[x][0],l,mid,L,R)) return 1;
    		if(mid<R&&query(ch[x][1],mid+1,r,L,R)) return 1;
    		return 0;
    	}
    }
    
    int n,m,root[N*2];
    std::vector<int> e[N*2];
    
    struct SAM {
    	struct Node {
    		int ch[26],prt,mxl,tar;
    	} t[N*2];
    	int cnt,lst;
    	inline void clear() {
    		for(int i=1; i<=cnt; ++i) memset(&t[i],0,sizeof t[i]);
    		cnt=lst=1;
    	}
    	inline int extend(int c,int pos) {
    		int p=lst,x=lst=++cnt;
    		t[x].tar=pos;
    		t[x].mxl=t[p].mxl+1;
    		while(p&&!t[p].ch[c]) t[p].ch[c]=x,p=t[p].prt;
    		if(!p) t[x].prt=1;
    		else {
    			int q=t[p].ch[c];
    			if(t[q].mxl==t[p].mxl+1) t[x].prt=q;
    			else {
    				int k=++cnt; 
    				t[k]=t[q]; 
    				t[k].mxl=t[p].mxl+1;
    				t[q].prt=t[x].prt=k;
    				while(p&&t[p].ch[c]==q) t[p].ch[c]=k,p=t[p].prt;
    			}
    		}
    		return x;
    	}
    	inline void dfs(int x) {
    		for(int y:e[x]) {
    			dfs(y);
    			root[x]=SGT::merge(root[x],root[y],1,N);
    		}
    	}
    	inline void build(char *s,int N,bool sgt) {
    		clear();
    		for(int i=1; i<=N; ++i) {
    			int x=extend(s[i]-'a',i);
    			if(sgt) SGT::insert(root[x],1,N,i);
    		}
    		if(sgt) {
    			for(int i=2; i<=cnt; ++i) e[t[i].prt].push_back(i);
    			dfs(1);
    		}
    	}
    	void key() {
    		printf("total nodes: %d
    ",cnt);
    		for(int i=1; i<=cnt; ++i) {
    			printf(" %d %d %d
    ",t[i].mxl,t[i].tar,t[i].prt);
    		}
    	}
    } S,T;
    
    char s[N];
    int L,R,Q,lim[N];
    
    inline long long calc() {
    	scanf("%s%d%d",s+1,&L,&R);
    	T.build(s,m=strlen(s+1),0);
    	//T.key();
    	int now=1,len=0;
    	for(int i=1; i<=m; ++i) {
    		int c=s[i]-'a';
    		while(1) {
    			//printf("<%d %d> ",now,len);
    			if(SGT::query(root[S.t[now].ch[c]],1,n,L+len,R)) {
    				//printf(" ent ");
    				len++;
    				now=S.t[now].ch[c];
    				break;
    			} else {
    				if(now==1) break;
    				--len;
    				if(len==S.t[S.t[now].prt].mxl) now=S.t[now].prt; 
    			}
    		}
    		lim[i]=len;
    	}
    	long long ans=0;
    	for(int i=1; i<=T.cnt; ++i) {
    		ans+=T.t[i].mxl-T.t[T.t[i].prt].mxl;
    		ans-=std::max(0,std::min(T.t[i].mxl,lim[T.t[i].tar])-T.t[T.t[i].prt].mxl);
    	}
    	return ans;
    }
    
    int main() {
    	freopen("name.in","r",stdin);
    	freopen("name.out","w",stdout);
    	scanf("%s%d",s+1,&Q);
    	S.build(s,n=strlen(s+1),1); 
    	//S.key();
    	while(Q--) printf("%lld
    ",calc());
    	return 0;
    }
    
  • 相关阅读:
    【Linux】【Services】【SaaS】Docker+kubernetes(11. 构建复杂的高可用网络)
    【Linux】【Services】【SaaS】Docker+kubernetes(10. 利用反向代理实现服务高可用)
    socketserver.py
    Python 字符中文坑
    H3C对接华为S5700s---配置链路聚合
    format使用
    python 登入接口
    python 多级菜单
    Windows 下安装MongoDB
    Gerrit 服务器安装插件
  • 原文地址:https://www.cnblogs.com/nosta/p/10809950.html
Copyright © 2020-2023  润新知