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';
      }
}
 
 

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.