$n leq 100000$的01串(其实啥串都行),给$m leq 100000$个询问,每次问$[L,R]$,回答:前缀$L,L+1,...,R$中,任意两个的最长公共后缀的长度。
这种前缀后缀的询问,无脑先建个后缀树先,反串的后缀树正串的sam哦。
然后现在问题就是:每次问一个区间的点集,问他们俩俩LCA的权值最大的一个。
可以发现一个点对答案有贡献的时候,他子树里至少选了两个点。如果询问按右端点从小到大排序,从小到大动态把点加进去,那我只要知道倒数第二次覆盖他的是谁即可。为啥呢?首先谁覆盖他他对答案贡献一样嘛因为一个点代表的串的长度是不会变的,然后右端点固定的时候我肯定希望那个上次覆盖他的点尽量大,这样就能贡献给更多的区间,您比如说这倒数第二次覆盖他的是x,倒数第三次是y,那由于我从小到大加的所以x>y,然后x能贡献的区间[L,R],y可能贡献不到,在y<L<x时发生这种情况。
慢着还有个问题这个覆盖复杂度不大对?一直往上跳的操作不是LCT咩?
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<math.h> 5 //#include<queue> 6 #include<algorithm> 7 //#include<iostream> 8 //#include<assert.h> 9 using namespace std; 10 11 int n,m; 12 #define maxn 200011 13 14 struct BIT 15 { 16 int a[maxn],n; 17 void clear(int m) {n=m;} 18 void add(int x,int v) {if (x<1 || x>n) return; x=n-x+1; for (;x<=n;x+=x&-x) a[x]=max(a[x],v);} 19 int query(int x) 20 { 21 int now=0,tot=0; 22 for (int i=18;i>=0;i--) 23 { 24 now+=(1<<i); 25 if (now<=n && max(tot,a[now])<x) tot=max(tot,a[now]); 26 else now-=(1<<i); 27 } 28 return n-(now+1)+1; 29 } 30 }bit; 31 //xia biao chuan jin bit shi ji de fan guo lai 32 33 struct SAM 34 { 35 struct Node 36 { 37 int ch[2],pos,pre; 38 }a[maxn<<1]; 39 int size,last,num[maxn]; 40 SAM() {size=0; last=0; a[0].pre=-1; a[0].pos=0;} 41 42 void insert(int id,int p) 43 { 44 int x=++size,y=last; last=x; num[p]=x+1; 45 a[x].pos=p; a[x].ch[0]=a[x].ch[1]=0; 46 for (;~y && !a[y].ch[id];y=a[y].pre) a[y].ch[id]=x; 47 if (!~y) a[x].pre=0; 48 else if (a[a[y].ch[id]].pos==a[y].pos+1) a[x].pre=a[y].ch[id]; 49 else 50 { 51 int z=a[y].ch[id],w=++size; a[w]=a[z]; a[w].pos=a[y].pos+1; 52 a[z].pre=a[x].pre=w; 53 for (;~y && a[y].ch[id]==z;y=a[y].pre) a[y].ch[id]=w; 54 } 55 } 56 }sam; 57 58 struct LCT 59 { 60 struct Node 61 { 62 int son[2],fa; 63 int tag,Max,v; 64 }a[maxn<<1]; 65 int n; 66 void clear(int m) {n=m;} 67 void up(int x) {if (!x) return; Node &b=a[x]; b.Max=max(b.v,max(a[b.son[0]].Max,a[b.son[1]].Max));} 68 void down(int x) {Node &b=a[x]; a[b.son[0]].tag=b.tag; a[b.son[1]].tag=b.tag;} 69 bool isroot(int x) {Node &b=a[x]; return !b.fa || (a[b.fa].son[0]!=x && a[b.fa].son[1]!=x);} 70 int sta[maxn],top; 71 void download(int x) 72 { 73 top=0; sta[++top]=x; for (int i=x;!isroot(i);i=a[i].fa) sta[++top]=a[i].fa; 74 while (top) down(sta[top--]); 75 } 76 void rotate(int x) 77 { 78 int y=a[x].fa,z=a[y].fa; 79 bool w=(x==a[y].son[0]); 80 a[x].fa=z; if (!isroot(y)) a[z].son[y==a[z].son[1]]=x; 81 a[y].son[w^1]=a[x].son[w]; if (a[x].son[w]) a[a[x].son[w]].fa=y; 82 a[x].son[w]=y; a[y].fa=x; 83 up(y); up(z); 84 } 85 void splay(int x) 86 { 87 if (!x) return; 88 download(x); 89 while (!isroot(x)) 90 { 91 int y=a[x].fa,z=a[y].fa; 92 if (!isroot(y)) {if ((x==a[y].son[0])^(y==a[z].son[0])) rotate(x); else rotate(y);} rotate(x); 93 } 94 up(x); 95 } 96 void access(int x,int col) 97 { 98 int y=0; while (x) 99 { 100 splay(x); a[x].son[1]=0; up(x); 101 bit.add(a[x].Max,a[x].tag); 102 a[x].son[1]=y; up(x); 103 y=x; x=a[x].fa; 104 } 105 a[y].tag=col; 106 } 107 }t; 108 109 void buildtree() 110 {for (int i=1;i<=sam.size;i++) t.a[i+1].fa=sam.a[i].pre+1,t.a[i+1].v=t.a[i+1].Max=sam.a[i].pos;} 111 112 struct Ques{int id,l,next;}ques[maxn<<1]; int fques[maxn],lq=2; 113 void in(int x,int L,int id) {Ques &e=ques[lq]; e.id=id; e.l=L; e.next=fques[x]; fques[x]=lq++;} 114 115 char s[maxn]; int ans[maxn]; 116 int main() 117 { 118 scanf("%d%d",&n,&m); 119 scanf("%s",s+1); 120 for (int i=1;i<=n;i++) sam.insert(s[i]-'0',i); 121 t.clear(sam.size+1); buildtree(); 122 123 for (int i=1,L,R;i<=m;i++) scanf("%d%d",&L,&R),in(R,L,i); 124 bit.clear(n); 125 for (int i=1;i<=n;i++) 126 { 127 t.access(sam.num[i],i); 128 for (int j=fques[i];j;j=ques[j].next) 129 { 130 Ques &e=ques[j]; 131 ans[e.id]=bit.query(e.l); 132 } 133 } 134 135 for (int i=1;i<=m;i++) printf("%d ",ans[i]); 136 return 0; 137 }