2021ccpc桂林J-SuffixAutomaton(后缀自动机+线段树)

更新时间:2023-07-03 09:26:55 阅读: 评论:0

2021ccpc桂林J-SuffixAutomaton(后缀⾃动机+线段树)
赛中到最后时间不够,写的时候脑袋混乱,后来因为不明错误样例都没调过...没拿⾦我背⼤锅。
赛后重新整理下思路,直接A了,哎....
思路:⾸先对⼦串字典序问题有个经典做法是反串建后缀⾃动机,然后建出parent树,其中在建树时边权是⼦节点⽐⽗节点刚好多出⼀个的字符,这样这个树的dfs序就刚好是⼦串的字典序了,然后题⽬中是在⼦串长度相等的基础上⽐较字典序,否则⽐较长度,那么对于树上的某⼀个节点,由于其代表的⼦串长度是连续的,所以可以利⽤差分的思想,将这个⼦串的信息存到差分数组的该⼦串的最短长度和最长长度+1上,代表这段区间的长度含这个⼦串。然后就先按从⼩到⼤离线询问,然后对于每个询问,算出这个询问代表的⼦串的长度k和在这个长度⾥排第⼏x,然后将差分数组的指针⼀步步移到当前长度,⼀边移动⼀边更新线段树(将相应的dfs序更新),然后查询线段树中第x个出现的下标即可。由于最后答案要求是最左边出现的⼦串的下标,也就是要求反串后最右下标,可以从parent树从叶⼦往上更新位置的最⼤值。
越想越⽓...
#include <iostream>
#include <cstdio>
英语小对话#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <t>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
/
/#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000000 + 100;
const int INF = 0x7fffffff;
const int mod = 998244353;
const ll mod1 = 998244353;
const ll ba = 137;
const double Pi = acos(-1.0);
const int G = 3;
struct state
{
int len, link;
//std::map<char, int> next;
caucus
int nxt[26];
int pos;
};
const int MAXLEN = 1000000 + 5;
state st[MAXLEN * 2];
int sz, last;
void sam_init()
{
memt(st[0].nxt, 0, sizeof(st[0].nxt));
sz = 0;
st[0].len = 0;
st[0].link = -1;
sz++;
last = 0;
}
int cur;
void sam_extend(char c, int id)
{
cur = sz++;
st[cur].pos = id;
st[cur].len = st[last].len + 1;
int p = last;
while (p != -1 && !st[p].nxt[c - 'a'])
{
st[p].nxt[c - 'a'] = cur;
p = st[p].link;
}
if (p == -1)
{
st[cur].link = 0;
}
el
{
int q = st[p].nxt[c - 'a'];
if (st[p].len + 1 == st[q].len)
{
st[cur].link = q;
}
int clone = sz++;
st[clone].len = st[p].len + 1;
memcpy(st[clone].nxt, st[q].nxt, sizeof(st[clone].nxt));          //  st[clone].pos = st[q].pos;
//st[clone].next = st[q].next;
st[clone].link = st[q].link;
while (p != -1 && st[p].nxt[c - 'a'] == q)
{
st[p].nxt[c - 'a'] = clone;
p = st[p].link;
}
重庆翻译公司st[q].link = st[cur].link = clone;
}
}
last = cur;
//siz[cur]=1;
}
int len[maxn];
int a[maxn*2];
int n;
void getSiz()
{
for(int i=1;i<sz;i++)
{
len[st[i].len]++;
}
for(int i=n;i>=1;i--)
{
len[i]+=len[i+1];
}
for(int i=1;i<sz;i++)
{
a[len[st[i].len]--]=i;
}
for(int i=1;i<sz;i++)
{
int p=a[i];
st[st[p].link].pos=max(st[st[p].link].pos,st[p].pos);
}
}
char s[maxn];
struct node
{真相只有一个用日语怎么说
int id;
ll x;
} qu[maxn];
bool cmp(node a, node b)
{
return a.x < b.x;
}
struct NNode
{
int to;
int str;
NNode(int tt = 0, int ss = 0)
couchba
{
to = tt;
str = ss;
}
};
vector<NNode> edge[maxn];
int in[maxn * 2];
int vis[maxn * 2];
int cnt;
void dfs(int x)
{
in[x] = ++cnt;
vis[cnt] = x;
//cout<<222<<' '<<cnt<<' '<<x<<endl;
for (int i = 0; i < (int)edge[x].size(); i++)
{
dfs(edge[x][i].to);
}
}
struct pp
{
int id;
int f;
pp(int ii, int ff)
{
id = ii;
};
vector<pp> v[maxn];
ll sum[maxn];
pair<int, int> ans[maxn];
struct Node
{
int l, r, sum;
} tree[maxn * 8];
void build(int i, int l, int r)
{
/
/cout<<i<<' '<<l<<' '<<r<<endl;
tree[i].l = l;
tree[i].r = r;
if (l == r)
{
tree[i].sum = 0;
return;
}
int mid = (l + r) >> 1;
build(i * 2, l, mid);
build(i * 2 + 1, mid + 1, r);
tree[i].sum = 0;
}
void update(int i, int k, int x)
{
if (tree[i].l == tree[i].r)
{
tree[i].sum += x;
return;
}
if (tree[i * 2].r >= k)
update(i * 2, k, x);
if (tree[i * 2 + 1].l <= k)
update(i * 2 + 1, k, x);
tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
int query(int i, int k)
{
//  cout<<i<<' '<<tree[i].l<<' '<<tree[i].r<<' '<<tree[i*2].sum<<' '<<k<<endl;郑州化妆师培训>英文翻译中文转换器
if (tree[i].l == tree[i].r)
{
return tree[i].l;
}
int res;
if (tree[i * 2].sum >= k)
res = query(i * 2, k);
el
我很好英语
res = query(i * 2 + 1, k - tree[i * 2].sum);
return res;
}
int dp[maxn];
bool cmp2(NNode a, NNode b)
{
return a.str < b.str;
}
int main()
{
scanf("%s", s + 1);
int len = strlen(s + 1);
n=len;
for (int i = 1; i <= len / 2; i++)
{
swap(s[i], s[len - i + 1]);
}
sam_init();
for (int i = 1; i <= len; i++)
sam_extend(s[i], i);
getSiz();
//  printf("%s",s+1);
for (int i = 1; i < sz; i++)
{
edge[st[i].link].push_back(NNode(i, s[st[i].pos - st[st[i].link].len] - 'a'));
//  cout<<222<<' '<<st[i].pos<<' '<<st[st[i].link].len<<' '<<s[st[i].pos-st[st[i].link].len]-'a'<<endl;    }
for (int i = 0; i < sz; i++)
{
sort(edge[i].begin(), edge[i].end(), cmp2);
}
dfs(0);
for (int i = 1; i < sz; i++)
{
v[st[st[i].link].len + 1].push_back(pp(i, 0));
v[st[i].len + 1].push_back(pp(i, 1));
dp[st[st[i].link].len + 1]++;
dp[st[i].len + 1]--;
defects}
for (int i = 1; i <= len; i++)
{
sum[i] = sum[i - 1] + dp[i];
//  cout<<111<<' '<<i<<' '<<sum[i]<<endl;
}
我爱你英语
for (int i = 1; i <= len; i++)
{
sum[i] += sum[i - 1];
}
int q;
scanf("%d", &q);
for (int i = 1; i <= q; i++)
{
scanf("%lld", &qu[i].x);
qu[i].id = i;
}
sort(qu + 1, qu + 1 + q, cmp);
//cout<<len<<endl;
build(1, 1, sz);
int now = 1;
for (int i = 1; i <= q; i++)
{
int le = lower_bound(sum + 1, sum + 1 + len, qu[i].x) - sum;        int k = qu[i].x - sum[le - 1];
//  cout<<le<<' '<<k<<endl;
if (le > len)
{
ans[qu[i].id].first = -1;
ans[qu[i].id].cond = -1;
continue;
}
while (now <= le)
{
for (auto j : v[now])
{
if (j.f == 0)
{
update(1, in[j.id], 1);
// cout<<in[j.id]<<' '<<1<<endl;
}
el
{
update(1, in[j.id], -1);
}
}
now++;
}
int p = query(1, k);
//  cout<<111<<' '<<k<<' '<<vis[p]<<endl;
p=vis[p];
//  while(st[st[p].link].len>=le) p=st[p].link;
int l = st[p].pos - le + 1;
int r = st[p].pos;
ans[qu[i].id].first = len - r + 1;
ans[qu[i].id].cond = len - l + 1;
}
for (int i = 1; i <= q; i++)
{
printf("%d %d\n", ans[i].first, ans[i].cond);
}
//  system("pau");
}

本文发布于:2023-07-03 09:26:55,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/165638.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:长度   线段   反串   差分   动机   数组   后缀   节点
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图