Prefix
Time Limit: 2000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 519 Accepted Submission(s): 157
Problem Description
Alice gets N strings. Now she has Q questions to ask you. For each question, she wanna know how many different prefix strings between Lth and Rth strings. It's so easy right? So solve it!
Input
The input contains multiple test cases.
For each test case, the first line contains one integer N(1≤N≤100000) . Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer Q(1≤Q≤100000) . We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.
For each test case, the first line contains one integer N(1≤N≤100000) . Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer Q(1≤Q≤100000) . We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.
Output
For each question, output the answer.
Sample Input
3 abc aba baa 3 0 2 0 1 1 1
Sample Output
7 6 3
思路 因为 f (x) 是一个包含z的函数 而 z 是基于每次给出的答案 (初始的z 是 0) 所以强制在线
题目说 所以建一棵字典树 节点保存最后出现的字符串的编号
在建树的时候 把每个字符串走过的节点的数据存进另一个数组arr 并更新这个节点
可以再开个数组 nb 保存一下每个字符串添加进去 字典树的节点数 (1 ~ i 的前缀数)
然后我们可以 得出 ANS = nb[r] - nb[l-1] + ( arr[l 的首字符位置 ] ~~ arr[r 尾字符] 中比 l 小的个数 )
统计 比l 小的个数的 用主席树维护
昨天TLE到- - 于是今天看了下主席树的讲解 也不知道这个 嗯 算不算正常的主席树
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#define pi acos(-1.0)
#define inf 1<<29
#define INF 0x3f3f3f3f
#define zero 1e-8
const int li[] = { -1, 0, 1, 0};
const int lj[] = {0, -1, 0, 1};
using namespace std;
const int N = 100007 + 107;
struct node {
int next[27];
int cnt;
} tree[N];
int fin, least;
struct lo {
int l, r, data;
lo(){l=r=data=0;}
void show()
{
cout << "l: " << l << " r: " << r << " data: " << data << endl;
}
} cmtree[N * 21];
int root[N];
int pt;
int sum;
int nb[N], arr[21*N], lef[N], arrnum;
char str[N];
int tot, treenum;
int cnt;
void init()
{
arrnum = treenum = 0;
memset(tree,0,sizeof(tree));
memset(cmtree,0,sizeof(cmtree));
sum=pt = 0;
}
void build(int i, int num, int id)
{
if (str[i] == '\0') return;
if (!tree[num].next[str[i] - 'a']) {
tree[num].next[str[i] - 'a'] = (++treenum);
arr[++arrnum] = id;
} else {
arr[++arrnum] = tree[tree[num].next[str[i] - 'a']].cnt;
}
tree[tree[num].next[str[i] - 'a']].cnt = id;
build(i + 1, tree[num].next[str[i] - 'a'], id);
}
void show()
{
for (int i = 0; i < 17; ++i)
cout << "i: " << i << " arr: " << arr[i] << " lef" << lef[i] <<
" nb" << nb[i] << endl;
}
void build(int from, int node, int left, int right, int arrow)
{
++pt;
int now = pt;
if (arrow == 1) cmtree[from].l = pt;
else cmtree[from].r = pt;
if (left == right) {
cmtree[pt].l = cmtree[pt].r = -1;
cmtree[pt].data = 0;
return;
}
build(now, node * 2, left, (left + right) / 2, 1);
build(now, node * 2 + 1, (left + right) / 2 + 1, right, 2);
return;
}
void update(int node, int left, int right, int from, int mod, int data, int arrow)
{
++pt;
int now = pt;
if (arrow == 1) cmtree[from].l = pt;
else cmtree[from].r = pt;
int mid = (left + right) / 2;
if (left == right) {
cmtree[pt].data = cmtree[mod].data + 1;
cmtree[pt].l = cmtree[pt].r = -1;
return;
}
if (data <= mid) {
update(node * 2, left, mid, pt, cmtree[mod].l, data, 1);
cmtree[now].r = cmtree[mod].r;
}
else {
update(node * 2 + 1, mid + 1, right, pt, cmtree[mod].r, data, 2);
cmtree[now].l = cmtree[mod].l;
}
cmtree[now].data = cmtree[cmtree[now].l].data + cmtree[cmtree[now].r].data;
}
void query(int node, int left, int right, int Begin, int End, int next)
{
if (left > End || right < Begin) return ;
if (left >= Begin && right <= End) {
sum += cmtree[next].data;
return;
}
int mid = (left + right) / 2;
query(node * 2, left, mid, Begin, End, cmtree[next].l);
query(node * 2 + 1, mid + 1, right, Begin, End, cmtree[next].r);
}
int main()
{
int n;
while (~scanf("%d", &n)) {
init();
for (int i = 1; i <= n; ++i) {
scanf("%s", str);
lef[i] = arrnum + 1;
build(0, 0, i);
nb[i] = treenum;
}
lef[n + 1] = arrnum + 1;
pt = 0;
root[0] = pt;
build(root[0], 1, 1, n, 1);
for (int i = 1; i <= arrnum; ++i) {
root[i] = ++pt;
update(1, 1, n, root[i], root[i - 1] + 1, arr[i], 1);
}
int m;
scanf("%d", &m);
int z = 0;
for (int i = 0; i < m; ++i) {
int l, r;
scanf("%d %d", &l, &r);
l = (z + l) % n + 1;
r = (z + r) % n + 1;
if(l > r) swap(l, r);
sum = fin = 0;
if (l > 1) {
query(1, 1, n, 1, l - 1, root[lef[r+1]-1] + 1);
int ans1 = sum;
sum = 0;
query(1, 1, n, 1, l - 1, root[lef[l]-1] + 1);
int ans2 = sum;
fin = ans1 - ans2;
}
z = nb[r] - nb[l - 1] + fin;
printf("%d\n", z);
}
}
return 0;
}