Showing posts with label Suffix Automaton. Show all posts
Showing posts with label Suffix Automaton. Show all posts

Monday, September 9, 2019

[Codeforces] B. String

Author            : Dipu Kumar Mohanto 
                    CSE, Batch - 6
                    BRUR.
Problem Statement : B. String
Source            : Codeforces
Category          : String
Algorithm         : Suffix Automaton, kth lexicographical substring
Verdict           : Accepted

  1. #include "bits/stdc++.h"  
  2.   
  3. using namespace std;  
  4.   
  5. static const int maxn = 2e5 + 5;  
  6.   
  7. struct State  
  8. {  
  9.       int len;  
  10.       int link;  
  11.       long long occ;  
  12.       long long word;  
  13.       map <charint> Next;  
  14.   
  15.       State() {}  
  16.       void clean()  
  17.       {  
  18.             len = 0;  
  19.             link = -1;  
  20.             occ = 0;  
  21.             word = 0;  
  22.             Next.clear();  
  23.       }  
  24. } st[maxn * 2];  
  25.   
  26. int sz;  
  27. int last;  
  28.   
  29. void init()  
  30. {  
  31.       sz = 0;  
  32.       last = 0;  
  33.       for (int i = 0; i < maxn * 2; i++) st[i].clean();  
  34.       sz++;  
  35. }  
  36.   
  37. void SAM(char ch)  
  38. {  
  39.       int cur = sz++;  
  40.       st[cur].len = st[last].len + 1;  
  41.       int p;  
  42.       for (p = last; p != -1 && !st[p].Next.count(ch); p = st[p].link)  
  43.       {  
  44.             st[p].Next[ch] = cur;  
  45.       }  
  46.       if (p == -1)  
  47.       {  
  48.             st[cur].link = 0;  
  49.       }  
  50.       else  
  51.       {  
  52.             int q = st[p].Next[ch];  
  53.             if (st[p].len + 1 == st[q].len)  
  54.             {  
  55.                   st[cur].link = q;  
  56.             }  
  57.             else  
  58.             {  
  59.                   int clone = sz++;  
  60.                   st[clone].len = st[p].len + 1;  
  61.                   st[clone].Next = st[q].Next;  
  62.                   st[clone].link = st[q].link;  
  63.                   for ( ; p != -1 && st[p].Next[ch] == q; p = st[p].link)  
  64.                   {  
  65.                         st[p].Next[ch] = clone;  
  66.                   }  
  67.                   st[q].link = st[cur].link = clone;  
  68.             }  
  69.       }  
  70.       last = cur;  
  71. }  
  72.   
  73. void allTerminal()  
  74. {  
  75.       int cur = last;  
  76.       while (cur > 0)  
  77.       {  
  78.             st[cur].occ += 1;  
  79.             cur = st[cur].link;  
  80.       }  
  81. }  
  82.   
  83. void dfs(int u = 0)  
  84. {  
  85.       if (st[u].word) return;  
  86.       for (auto it : st[u].Next)  
  87.       {  
  88.             int v = it.second;  
  89.             dfs(v);  
  90.             st[u].occ += st[v].occ;  
  91.             st[u].word += st[v].word;  
  92.       }  
  93.       st[u].word += st[u].occ;  
  94. }  
  95.   
  96. void kthLex(int u, int k, string &s)  
  97. {  
  98.       if (k <= 0) return;  
  99.       for (auto it : st[u].Next)  
  100.       {  
  101.             int v = it.second;  
  102.             if (st[v].word >= k)  
  103.             {  
  104.                   s.push_back(it.first);  
  105.                   return void(kthLex(v, k - st[v].occ, s));  
  106.             }  
  107.             else  
  108.             {  
  109.                   k -= st[v].word;  
  110.             }  
  111.       }  
  112. }  
  113.   
  114. int main()  
  115. {  
  116.       ios_base::sync_with_stdio(false);  
  117.       cin.tie(nullptr);  
  118.       cout.tie(nullptr);  
  119.   
  120.       #ifndef ONLINE_JUDGE  
  121.             freopen("in.txt""r", stdin);  
  122.       #endif // ONLINE_JUDGE  
  123.   
  124.       string s;  
  125.       int k;  
  126.       cin >> s >> k;  
  127.       init();  
  128.       for (char ch : s) SAM(ch);  
  129.       allTerminal();  
  130.       dfs();  
  131.       string ans;  
  132.       kthLex(0, k, ans);  
  133.       if (ans.empty()) ans = "No such line.";  
  134.       cout << ans << endl;  
  135. }  

Saturday, August 24, 2019

[Toph] Unique Substrings Query

Author            : Dipu Kumar Mohanto 
                    CSE, Batch - 6
                    BRUR.
Problem Statement : Unique Substrings Query
Source            : Toph.co
Category          : Data Structure, String
Algorithm         : Suffix Automaton, Binary Indexed Tree, Persistent Segment Tree
Verdict           : Accepted

#include "bits/stdc++.h"
 
using namespace std;
 
#define ll            long long int
#define endl          '\n'
 
static const int maxn = 2e3 + 5;
static const ll mod = 1e9 + 7;
static const int Max = 6e6 + 7;
 
int N = 1000 + 2;
ll Bit[maxn];
 
ll add(ll a, ll b)
{
      a = (a + b);
      return a;
}
 
void bitUpdate(int pos, ll val)
{
      while (pos <= N)
      {
            Bit[pos] = add(Bit[pos], val);
            pos += (pos & -pos);
      }
}
 
void rangeUpdate(int l, int r, ll val)
{
      bitUpdate(l, val);
      bitUpdate(r + 1, -val);
}
 
ll read(int pos)
{
      ll sum = 0;
      while (pos > 0)
      {
            sum = add(sum, Bit[pos]);
            pos -= (pos & -pos);
      }
      return sum;
}
 
struct state
{
      int len, link;
      map <char, int> next;
} st[maxn * 2];
 
int sz, last;
 
void init()
{
      sz = last = 0;
      st[0].len = 0;
      st[0].link = -1;
      st[0].next.clear();
      for (int i = 1; i < maxn * 2; i++)
      {
            st[i].len = 0;
            st[i].link = 0;
            st[i].next.clear();
      }
      ++sz;
}
 
void szExtend(char c)
{
      int l, r;
      int cur = sz++;
      st[cur].len = st[last].len + 1;
      int p;
      for (p = last; p != -1 && !st[p].next.count(c); p = st[p].link)
      {
            st[p].next[c] = cur;
      }
      if (p == -1)
      {
            st[cur].link = 0;
      }
      else
      {
            int q = st[p].next[c];
            if (st[p].len + 1 == st[q].len)
            {
                  st[cur].link = q;
            }
            else
            {
                  int clone = sz++;
                  st[clone].len = st[p].len + 1;
                  st[clone].next = st[q].next;
                  st[clone].link = st[q].link;
                  for ( ; p != -1 && st[p].next[c] == q; p = st[p].link)
                  {
                        st[p].next[c] = clone;
                  }
                  l = st[ st[q].link ].len;
                  r = st[q].len;
                  assert(l+1 <= r);
                  rangeUpdate(l+1, r, -1);
                  st[q].link = st[cur].link = clone;
                  l = st[ st[q].link ].len;
                  r = st[q].len;
                  assert(l+1 <= r);
                  rangeUpdate(l+1, r, 1);
                  l = st[ st[clone].link ].len;
                  r = st[clone].len;
                  assert(l+1 <= r);
                  rangeUpdate(l+1, r, 1);
            }
      }
      l = st[ st[cur].link ].len;
      r = st[cur].len;
      assert(l+1 <= r);
      rangeUpdate(l+1, r, 1);
      last = cur;
}
 
 
struct Node
{
      ll st;
      int lft, rgt;
      Node(ll st = 0, int lft = 0, int rgt = 0) : st(st), lft(lft), rgt(rgt) {}
} Tree[Max];
 
int version[maxn];
int NODES;
//int N = 1000;
 
int update(int root, int a, int b, int pos, ll val)
{
      int newNode = ++NODES;
      Tree[newNode] = Tree[root];
      if (a == b)
      {
            Tree[newNode].st += val;
            return newNode;
      }
      int mid = (a + b) >> 1;
      if (pos <= mid) Tree[newNode].lft = update(Tree[newNode].lft, a, mid, pos, val);
      else Tree[newNode].rgt = update(Tree[newNode].rgt, mid + 1, b, pos, val);
      Tree[newNode].st = Tree[ Tree[newNode].lft ].st + Tree[ Tree[newNode].rgt ].st;
      return newNode;
}
 
ll query(int proot, int root, int a, int b, int i, int j)
{
      if (a > b or a > j or b < i) return 0;
      if (a >= i && b <= j)
      {
            return Tree[root].st - Tree[proot].st;
      }
      int mid = a + b >> 1;
      ll p = query(Tree[proot].lft, Tree[root].lft, a, mid, i, j);
      ll q = query(Tree[proot].rgt, Tree[root].rgt, mid + 1, b, i, j);
      return p + q;
}
 
int originalVersion[maxn];
 
signed main()
{
      ios_base::sync_with_stdio(false);
      cin.tie(nullptr);
      cout.tie(nullptr);
      cout << fixed << setprecision(8);
 
      #ifndef ONLINE_JUDGE
            freopen("in.txt", "r", stdin);
      #endif // ONLINE_JUDGE
 
      int n, m;
      cin >> n >> m;
      string s;
      cin >> s;
      s = "#" + s;
 
      NODES = 0;
      version[0] = 0;
      for (int i = 0; i < maxn; i++) Tree[i] = Node();
 
      int ptr = 0;
      originalVersion[n + 1] = 0;
      init();
      int len = 0;
      for (int i = n; i >= 1; i--)
      {
            szExtend(s[i]);
            ++len;
            ++ptr;
            originalVersion[i] = ptr;
            bool isCreated = 0;
            for (int j = 1; j <= len; j++)
            {
                  ll val = read(j);
                  if (isCreated == 0)
                  {
                        version[ptr] = update(version[ptr - 1], 1, N, j, val);
                        isCreated = 1;
                  }
                  else
                  {
                        version[ptr] = update(version[ptr], 1, N, j, val);
                  }
            }
      }
      while (m--)
      {
            int L, R, P, Q;
            cin >> L >> R >> P >> Q;
            ll ans = query(version[ originalVersion[R + 1] ], version[ originalVersion[L] ], 1, N, P, Q);
            cout << ans << '\n';
      }
}