第一次做这种\(SAM\)带权值线段树合并的题 然而\(zjq\)神犇看完题一顿狂码就做出来了 \(Orz\)

首先把所有串当成一个串建\(SAM\) 我们对\(SAM\)上每个点 建一棵权值线段树 每个叶子节点表示一个匹配串能到达这个点的子串个数 这样我们对最后的\(SAM\)的权值线段树按\(parent\)树合并 询问的时候找到对应的\(SAM\)上的权值线段树直接查询就好了

具体的操作看代码吧~

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int>
#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define fi first
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef Devil_Gary
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define bug(x)
#define debug(...)
#endif
const int INF = 0x7fffffff;
const int N=1230010;
/*
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
inline int read(){int x=0,rev=0,ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return rev?-x:x;
}
pa operator * (const pa&A,const pa&B){return A.fi==B.fi?(A.se<B.se?A:B):(A.fi>B.fi?A:B);}
pa operator + (const pa&A,const pa&B){return mk(A.fi+B.fi,A.se);}
pa t[N*23];
char s[N];
int n,m,Q,c[N][27],par[N],len[N],fa[N][21],ls[N*23],rs[N*23],h[N],rt=1,sz=1,last=1,root[N],w[N],b[N],id;
void extend(int x){int np=++sz,p=last;len[np]=len[p]+1,last=np;for(;p&&!c[p][x];p=par[p]) c[p][x]=np;if(!p) par[np]=rt;else{int q=c[p][x];if(len[p]+1==len[q]) par[np]=q;else{int nq=++sz;len[nq]=len[p]+1,par[nq]=par[q],par[q]=par[np]=nq;memcpy(c[nq],c[q],sizeof c[nq]);for(;p&&c[p][x]==q;p=par[p]) c[p][x]=nq;}}
}
void modify(int&pos,int l,int r,int x){if(!pos) pos=++id; if(l==r){t[pos].fi++,t[pos].se=l;
//      cout<<t[pos].fi<<" "<<t[pos].se<<endl;return;}int mid=l+r>>1;if(x<=mid) modify(ls[pos],l,mid,x);else modify(rs[pos],mid+1,r,x);t[pos]=t[ls[pos]]*t[rs[pos]];
}
inline int merge(int x,int y,int l,int r)
{if (!x||!y) return x|y; int z=++id;if (l==r) {t[z]=t[x]+t[y];return z;}int mid=(l+r)>>1;ls[z]=merge(ls[x],ls[y],l,mid),rs[z]=merge(rs[x],rs[y],mid+1,r);t[z]=t[ls[z]]*t[rs[z]];return z;
}
pa Query(int pos,int l,int r,int nl,int nr){if(!pos) return mk(0,0);if(nl<=l&&r<=nr) return t[pos];int mid=l+r>>1;if(nr<=mid) return Query(ls[pos],l,mid,nl,nr);else if(nl>mid) return Query(rs[pos],mid+1,r,nl,nr);else return Query(ls[pos],l,mid,nl,nr)*Query(rs[pos],mid+1,r,nl,nr);
}
void topsort(){for(int i=1;i<=sz;i++) w[len[i]]++;for(int i=1;i<=sz;i++) w[i]+=w[i-1];for(int i=1;i<=sz;i++) b[w[len[i]]--]=i;for(int i=sz;i;i--){int j=b[i];if(par[j]) root[par[j]]=merge(root[par[j]],root[j],1,n);}
}
void get_fa(){for(int i=1;i<=sz;i++) fa[i][0]=par[i];for(int i=1;i<=20;i++) for(int j=1;j<=sz;j++) fa[j][i]=fa[fa[j][i-1]][i-1];
}
int get(int l,int r){int L=r-l+1,x=h[r];for(int i=20;~i;i--) if(len[fa[x][i]]>=L) x=fa[x][i];
//  -len[par[x]]-len[par[fa[x][i]]]return x;
}
int main(){
#ifdef Devil_Garyfreopen("in.txt","r",stdin);
#endifscanf("%s",s+1),m=strlen(s+1);for(int i=1;i<=m;i++) extend(s[i]-'a'),h[i]=last;n=read();for(int i=1;i<=n;i++){scanf("%s",s+1),m=strlen(s+1),extend(26);for(int j=1;j<=m;j++) extend(s[j]-'a'),modify(root[last],1,n,i);}
//  bug(sz);topsort(),get_fa();for(Q=read();Q;Q--){int l=read(),r=read(),pl=read(),pr=read(),x=get(pl,pr);pa ans=Query(root[x],1,n,l,r);if(!ans.fi) printf("%d 0\n",l);else printf("%d %d\n",ans.se,ans.fi);}
}

转载于:https://www.cnblogs.com/devil-gary/p/9057102.html

Codeforces 666E Forensic Examination SAM+权值线段树相关推荐

  1. Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)

    题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...

  2. 【bzoj2770】YY的Treap 权值线段树

    题目描述 志向远大的YY小朋友在学完快速排序之后决定学习平衡树,左思右想再加上SY的教唆,YY决定学习Treap.友爱教教父SY如砍瓜切菜般教会了YY小朋友Treap(一种平衡树,通过对每个节点随机分 ...

  3. 树套树 ----- P1975 [国家集训队]排队(树状数组套权值线段树求动态逆序对)

    解题思路: 首先我们知道交换两个数a[l]和a[r]a[l]和a[r]a[l]和a[r]影响到的区间是[l+1,r−1][l+1,r-1][l+1,r−1] 对于a[l]a[l]a[l],我们要减去[ ...

  4. 树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大

    题目链接 题目大意: 给你一个数组aaa,aaa有两个操作 询问aaa中[l,r][l,r][l,r]区间里面第kkk小的数是哪个? 修改axa_xax​为yyy 解题思路: 首先我们知道权值线段树是 ...

  5. codevs1688 求逆序对(权值线段树)

    1688 求逆序对  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果 题目描述 Description 给定一个序列a1,a2,-,an,如 ...

  6. 【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】

    题意:给你一个序列,求满足要求的子序列个数,其中要求为: 1.子序列的max-子序列长度len<=k 2.子序列中不出现重复的数字 题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个 ...

  7. HDU-5249 KPI(STL or 权值线段树)

    题目链接 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请 ...

  8. Governing sand(权值线段树/主席树)

    链接:https://ac.nowcoder.com/acm/contest/887/C 来源:牛客网 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 65536K,其他语言13107 ...

  9. Minimum Inversion Number HDU - 1394(权值线段树/树状数组)

    The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that s ...

最新文章

  1. Windows下查看dll被哪个进程调用
  2. 解决WINCE6.0新建工程编译出错的问题
  3. error response from daemon_Scrapy 框架-模拟登录-Request、Response
  4. Ubuntu下一个好用的终端
  5. Android 整体设计及背后意义
  6. 如何利用光衰减器测试光纤收发器的灵敏度?
  7. 1月16日学习内容整理:存储库MongoDB之文档的增删改查操作补充
  8. BZOJ3437 小P的牧场
  9. Windows Phone 获取联系人
  10. qprocess start怎么判断是否结束_致恋爱中的我们,怎么样来判断一个女人是否在骗你?...
  11. OptiCoupe 6:光学切割面板和型材切割优化[OptiCut]
  12. 微盟致远OA聚水潭YonSuite系统对接集成整体解决方案
  13. 开局一张图,理解Vuex
  14. python使用大数据分析师工资待遇_2020年大数据分析师工资多少
  15. ESP32 Uart串口控制器
  16. 后端知识点:互联网中B端客户和C端客户的区别
  17. PHP即充宝v3.0实例
  18. 毕马威明确从事区块链行业所需的四大技能
  19. c语言if函数括号内大于零,c语言中if函数后面的小括号内能写2个判断条件吗?...
  20. 最新PHP软文发稿新闻文章发布自助推广平台源码

热门文章

  1. 读书笔记 -- 推荐系统实践(1)
  2. SAP 公司代码全局参数设置及其意义
  3. IDEA系列新手上路(作者使用经历,长篇预警)
  4. Python实现knn分类算法(Iris 数据集)
  5. facebook语言_如何在Facebook上更改语言设置
  6. 解决overleaf打不开(reCaptcha失效)问题
  7. 华强北的AirPods耳机谁家比较靠谱?
  8. C# MediaPlayer的详细用法
  9. Joan Ganz Cooney将接受IBC2018卓越国际荣誉奖
  10. 麒麟OS和龙芯环境编译安装GreatSQL