Pseudo-Isomorphic Substrings


Problem Statement :


wo strings A and B, consisting of small English alphabet letters are called pseudo-isomorphic if

Their lengths are equal
For every pair (i,j), where 1 <= i < j <= |A|, B[i] = B[j], iff A[i] = A[j]
For every pair (i,j), where 1 <= i < j <= |A|, B[i] != B[j] iff A[i] != A[j]

Naturally, we use 1-indexation in these definitions and |A| denotes the length of the string A.

You are given a string S, consisting of no more than 105 lowercase alphabetical characters. For every prefix of S denoted by S', you are expected to find the size of the largest possible set of strings , such that all elements of the set are substrings of S' and no two strings inside the set are pseudo-isomorphic to each other.

if S = abcde
then, 1st prefix of S is 'a'
then, 2nd prefix of S is 'ab'
then, 3rd prefix of S is 'abc'
then, 4th prefix of S is 'abcd' and so on..

Input Format

The first and only line of input will consist of a single string S. The length of S will not exceed 10^5.

Constraints

1  <=   |  S  |   <=  10^5
S contains only lower-case english alphabets ('a' - 'z').


Output Format

Output N lines. On the ith line, output the size of the largest possible set for the first i alphabetical characters of S such that no two strings in the set are pseudo-isomorphic to each other.



Solution :



title-img


                            Solution in C :

In   C++  :








#include <algorithm>
#include <iostream>
#include <iomanip>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,102400000")


const int MaxLen = 200001;
const int MaxLog = 21;
int lg[MaxLen], tmp[200001];
int S[MaxLen];

struct SuffixArray
{
	int rank [MaxLen], SA[MaxLen], h[MaxLen], D[MaxLen];
	int n, dep , count_rank [MaxLen], f[MaxLog][MaxLen];
	void Build ()
	{
		for(int len = 1; len < n; len <<= 1)
		{
			fill ( count_rank , count_rank + 1 + n, 0);
			for (int i=1;i <=n;++ i)
			++ count_rank [ rank [SA[i]+ len ]];
			for (int i=1;i <=n;++ i)
			count_rank [i]+= count_rank [i -1];
			for (int i=n;i >0;--i)
			D[ count_rank [ rank [SA[i]+ len ]]--] = SA[i];
			fill ( count_rank , count_rank + 1 + n, 0);
			for (int i=1;i <=n;++ i)
			++ count_rank [ rank [SA[i ]]];
			for (int i=1;i <=n;++ i)
			count_rank [i]+= count_rank [i -1];
			for (int i=n;i >0;--i)
			SA[ count_rank [ rank [D[i]]] --] = D[i];
			copy (rank , rank + 1 + n, D);
			rank [SA [1]]=1;
			for (int i=2;i <=n;++ i)
			if(D[SA[i]] != D[SA[i -1]] ||
			D[SA[i]+ len] != D[SA[i -1] + len ])
			rank [SA[i ]]= rank [SA[i -1]]+1;
			else
			rank [SA[i ]]= rank [SA[i -1]];
			if( rank [SA[n]] == n) break ;
		}
	}
	int strsuf (int *p, int *q)
	{
		int ret =0;
		for (; *p == *q; ++p, ++q, ++ ret );
		return ret;
	}
	void CalcHeight ()
	{
		for (int i=1;i <=n;++ i)
		{
			if( rank [i] == 1)
			h[i] = 0;
			else
			if(i == 1 || h[i -1] <= 1)
			h[i]= strsuf (S+i, S+SA[ rank [i] -1]);
			else
			h[i]= strsuf (S+i+h[i -1] -1 ,
			S+SA[ rank [i] -1]+h[i -1] -1)+ h[i -1] -1;
			f [0][ rank [i]]=h[i];
		}
		dep =1;
		for (int len =1; len *2 <=n;len <<=1 , dep ++)
		for(int i=1; i+len *2 -1 <=n;++ i)
		f[dep ][i]= min(f[dep -1][ i],f[dep -1][ i+len ]);
	}
	void init ( int _n) // String Stored in (S +1)
	{
		lg[1] = 0;
		for(int i = 2; i <= _n; i++)
			lg[i] = lg[i/2] + 1;
		n = _n;
		memset (tmp ,0, sizeof ( tmp ));
		for (int i=1;i <=n;++ i)
		++ tmp[S[i ]];
		for (int i=1;i <=10000;++ i)tmp [i]+= tmp [i -1];
		for (int i=n;i >0;--i)
		SA[ tmp[S[i]] --]=i;
		rank [SA [1]]=1;
		for (int i=2;i <=n;++ i)
		if(S[SA[i]] != S[SA[i -1]])
		rank [SA[i]] = rank [SA[i -1]]+1;
		else
		rank [SA[i]] = rank [SA[i -1]];
		Build ();
		CalcHeight ();
	}
	inline int lcp( int a, int b)
	{ // lcp of S[a] and S[b]
		if(a == b) return n - a + 1;
		a = rank [a], b = rank [b];
		if(a > b) swap (a, b);
		int d = lg[b - a];
		if ((1 << d) == (b - a)) return f[d][a +1];
		else return min(f[d][a+1] , f[d][b -(1<<d )+1]);
	}
}mySA;


int n;
string s;
int prevSame[100001];
int prevSame_chr[26];

int sa[100011], rank_in_sa[100011];
int height[100011];
int link_left[100011], link_right[100011];
int minv_left[100011], minv_right[100011];
long long ans[100011];

bool cmpSuffix(int a, int b)
{
	for(int i = 0; i <= n; )
	{
		if(a + i > n) return true;
		if(b + i > n) return false;
		int v1 = prevSame[a+i], v2 = prevSame[b+i];
		if(v1 > i) v1 = 0;
		if(v2 > i) v2 = 0;
		if(v1 != v2)
			return v1 > v2;
		if(n <= 100)
			i ++;
		else
			i += max(1, mySA.lcp(a+i, b+i));

	}
	return 0;
}

int MAIN()
{
	cin >> s;
	n = s.length();
	s = " " + s;
	for(int i = 1; i <= n/2; i++)
		swap(s[i], s[n+1-i]);
	memset(prevSame_chr, 0xe, sizeof(prevSame_chr));
	for(int i = 1; i <= n; i++)
	{
		prevSame[i] = min(i, prevSame_chr[s[i]-'a']);
		prevSame[i] = i - prevSame[i];
		prevSame_chr[s[i]-'a'] = i;
		S[i] = prevSame[i];
	}
	mySA.init(n);
	for(int i = 1; i <= n; i++)
		sa[i] = i;
	sort(sa + 1, sa + 1 + n, cmpSuffix);
	for(int i = 1; i <= n; i++)
		rank_in_sa[sa[i]] = i;
	int curH = 0;
	for(int i = 1; i <= n; i++)
	{
		curH = max(0, curH - 26);
		if(i == n)
			height[rank_in_sa[i]] = 0;
		else
		{
			int t = sa[rank_in_sa[i]-1];
			while(true)
			{
				if(i + curH > n || t + curH > n)
					break;
				int v1 = prevSame[i+curH], v2 = prevSame[t+curH];
				
				if(v1 > curH) v1 = 0;
				if(v2 > curH) v2 = 0;
				if(v1 != v2) break;
				curH ++;
			}
			height[rank_in_sa[i]] = curH;
		}
	}

	sa[0] = 0;
	sa[n+1] = n+1;
	height[n+1] = 0;
	for(int i = 0; i <= n; i++)
	{
		int a = sa[i], b = sa[i+1], v = height[i+1];
		link_left[b] = a;
		link_right[a] = b;
		minv_left[b] = v;
		minv_right[a] = v;
	}

	for(int i = 1; i <= n; i++)
	{
		ans[i] = (n+1-i) - max(minv_left[i], minv_right[i]);
		
		int nv = min(minv_left[i], minv_right[i]);
		int a = link_left[i], b = link_right[i];
		link_left[b] = a;
		link_right[a] = b;
		minv_right[a] = nv;
		minv_left[b] = nv;
	}

	for(int i = n-1; i >= 1; i--)
		ans[i] += ans[i+1];

	for(int i = n; i >= 1; i--)
		cout << ans[i] << endl;
	
	return 0;
}

int main()
{
	#ifdef LOCAL_TEST
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif
	ios :: sync_with_stdio(false);
	cout << fixed << setprecision(16);
	return MAIN();
}








In   Java  :







import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Solution implements Runnable {
	static Random RND = new Random(7777L);
	static int MAX_LENGTH = 100000;
	static int ALPHA_SIZE = 26;
	static int HASH_BASE = BigInteger.probablePrime(17, RND).intValue();
	static int[] HASH_BASE_POWS = new int[MAX_LENGTH * 2];

	static {
		HASH_BASE_POWS[0] = 1;

		for (int i = 1; i < HASH_BASE_POWS.length; i++) {
			HASH_BASE_POWS[i] = HASH_BASE_POWS[i - 1] * HASH_BASE;
		}
	}

	char[] s;
	int length;
	int[][] charMaps;
	int[][] charPerms;
	int[][] distributedHashes;
	int[] hashPrefixes;
	Map<Long, Integer> lcpCache = new HashMap<Long, Integer>();

	void solve() throws IOException {
		s = new StringBuilder(in.readLine()).reverse().toString().toCharArray();
		length = s.length;
		charMaps = getCharMaps(s);
		charPerms = getCharPermutations(charMaps);
		distributedHashes = getDistributedHashes(s);
		hashPrefixes = precalcHashPrefixes(charPerms, distributedHashes);
		Integer[] suffixArray = getSuffixArray();
		final int[] suffixIndex = new int[length];

		for (int i = 0; i < length; i++) {
			suffixIndex[suffixArray[i]] = i;
		}

NavigableSet<Integer> viewedSuffixes = new TreeSet<Integer>(
new Comparator<Integer>() {
@Override
public int compare(Integer pos1, Integer pos2) {
return (suffixIndex[pos1] - suffixIndex[pos2]);
					}
				});

		long[] counts = new long[length + 1];

		for (int pos = length - 1; pos >= 0; pos--) {
			long intersectionSize = 0L;

			{
				Integer neigbourPos = viewedSuffixes.lower(pos);

				if (neigbourPos != null) {
	\intersectionSize = Math.max(intersectionSize,
		lcp(pos, neigbourPos));
				}
			}

			{
				Integer neigbourPos = viewedSuffixes.higher(pos);

				if (neigbourPos != null) {
					intersectionSize = Math.max(intersectionSize,
							lcp(pos, neigbourPos));
				}
			}

			counts[pos] = counts[pos + 1] + length - pos - intersectionSize;
			viewedSuffixes.add(pos);
		}

		for (int i = 0; i < length; i++) {
			out.println(counts[length - 1 - i]);
		}
	}

	Integer[] getSuffixArray() {
		Integer[] suffixArray = new Integer[length];

		for (int i = 0; i < length; i++) {
			suffixArray[i] = i;
		}

		Arrays.sort(suffixArray, new Comparator<Integer>() {
			@Override
			public int compare(Integer pos1, Integer pos2) {
				if (pos1.equals(pos2)) {
					return 0;
				}

				int lcp = lcp(pos1, pos2);

				if (lcp == length - pos1) {
					return -1;
				}

				if (lcp == length - pos2) {
					return +1;
				}

				return charMaps[pos1][s[pos1 + lcp] - 'a']
						- charMaps[pos2][s[pos2 + lcp] - 'a'];
			}
		});

		return suffixArray;
	}

	int lcp(int pos1, int pos2) {
		if (pos1 > pos2) {
			return lcp(pos2, pos1);
		}

		int leftBound = 0;
		int rightBound = length - pos2;
		int lcp = naiveLcp(pos1, pos2, Math.min(120, rightBound));

		if (lcp == -1) {
			leftBound = Math.min(15, rightBound);

			while (leftBound <= rightBound) {
				int middlePoint = (leftBound + rightBound) >> 1;

				if (equals(pos1, pos2, middlePoint)) {
					lcp = Math.max(lcp, middlePoint);
					leftBound = middlePoint + 1;
				} else {
					rightBound = middlePoint - 1;
				}
			}
		}

		return lcp;
	}

	int naiveLcp(int pos1, int pos2, int len) {
		int[] map1 = charMaps[pos1];
		int[] map2 = charMaps[pos2];

		for (int i = 0; i < len; i++) {
			if (map1[s[pos1 + i] - 'a'] != map2[s[pos2 + i] - 'a']) {
				return i;
			}
		}

		return -1;
	}

	boolean equals(int pos1, int pos2, int length) {
		if (pos1 > pos2) {
			return equals(pos2, pos1, length);
		}

		int hash1 = hash(pos1, length);
		int hash2 = hash(pos2, length);
		int hashAlingmentPower = HASH_BASE_POWS[pos2 - pos1];

		return hashAlingmentPower * hash1 == hash2;
	}

	int hash(int pos, int length) {
		int[] perm = charPerms[pos];
		int[] hashes = distributedHashes[pos + length];
		int hash = -hashPrefixes[pos];

		for (int rank = 0; rank < perm.length; rank++) {
			hash += hashes[perm[rank]] * rank;
		}

		return hash;
	}

	static int[][] getCharMaps(char[] s) {
		int length = s.length;
		int[][] linksToNext = getLinksToNext(s);
		int[][] maps = new int[length][ALPHA_SIZE];

		for (int offset = 0; offset < length; offset++) {
			int[] map = maps[offset];
			Arrays.fill(map, -1);
			int mapped = 0;
			map[s[offset] - 'a'] = mapped++;

			for (int pos = offset; pos < length;) {
				int nextPos = length;
				int nextChar = -1;

				for (int ch = 0; ch < ALPHA_SIZE; ch++) {
					if (map[ch] == -1) {
						if (nextPos > linksToNext[pos][ch]) {
							nextPos = linksToNext[pos][ch];
							nextChar = ch;
						}
					}
				}

				if (nextChar == -1) {
					break;
				}

				map[nextChar] = mapped++;
				pos = nextPos;
			}
		}

		return maps;
	}

	static int[][] getLinksToNext(char[] s) {
		int length = s.length;
		int[][] linksToNext = new int[length][ALPHA_SIZE];

		for (int[] row : linksToNext) {
			Arrays.fill(row, length);
		}

		for (int i = length - 2; i >= 0; i--) {
			System.arraycopy(linksToNext[i + 1], 0, linksToNext[i], 0,
					ALPHA_SIZE);
			linksToNext[i][s[i + 1] - 'a'] = i + 1;
		}

		return linksToNext;
	}

	static int[][] getDistributedHashes(char[] s) {
		int length = s.length;
		int[][] distributedHashes = new int[length + 1][ALPHA_SIZE];

		for (int i = 0; i < length; i++) {
			System.arraycopy(distributedHashes[i], 0, distributedHashes[i + 1],
					0, ALPHA_SIZE);
			distributedHashes[i + 1][s[i] - 'a'] += HASH_BASE_POWS[i];
		}

		return distributedHashes;
	}

	static int[][] getCharPermutations(int[][] charMaps) {
		int lenght = charMaps.length;
		int[][] charPerms = new int[lenght][];

		for (int pos = 0; pos < lenght; pos++) {
			charPerms[pos] = getCharPermutation(charMaps[pos]);
		}

		return charPerms;
	}

	static int[] getCharPermutation(int[] map) {
		int[] permutation = new int[ALPHA_SIZE];
		int last = 0;

		for (int ch = 0; ch < ALPHA_SIZE; ch++) {
			if (map[ch] != -1) {
				permutation[map[ch]] = ch;
				last = Math.max(last, map[ch]);
			}
		}

		return Arrays.copyOf(permutation, last + 1);
	}

	static int[] precalcHashPrefixes(int[][] charPerms,
			int[][] distributedHashes) {
		int length = charPerms.length;
		int[] hashPreffixes = new int[length];

		for (int pos = 0; pos < length; pos++) {
			int[] hashes = distributedHashes[pos];
			int[] perm = charPerms[pos];

			for (int rank = 0; rank < charPerms[pos].length; rank++) {
				hashPreffixes[pos] += hashes[perm[rank]] * rank;
			}
		}

		return hashPreffixes;
	}

	static Solution INSTANCE = new Solution();
	static boolean WRITE_LOG = true;
	static long STACK_SIZE = -1;

	public static void main(String[] args) throws IOException {
		try {
			if (STACK_SIZE < 0L) {
				INSTANCE.run();
			} else {
				new Thread(null, INSTANCE, "Solver", 1L << 24).start();
			}
		} catch (Throwable e) {
			e.printStackTrace();
			System.exit(999);
		}
	}

	@Override
	public void run() {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			out.close();
			in.close();
		} catch (Throwable e) {
			e.printStackTrace();
			System.exit(999);
		}
	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st = new StringTokenizer("");

	String nextToken() throws IOException {
		while (!st.hasMoreTokens()) {
			st = new StringTokenizer(in.readLine());
		}

		return st.nextToken();
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

	int[] nextIntArray(int size) throws IOException {
		int[] ret = new int[size];

		for (int i = 0; i < size; i++) {
			ret[i] = nextInt();
		}

		return ret;
	}

	long[] nextLongArray(int size) throws IOException {
		long[] ret = new long[size];

		for (int i = 0; i < size; i++) {
			ret[i] = nextLong();
		}

		return ret;
	}

	double[] nextDoubleArray(int size) throws IOException {
		double[] ret = new double[size];

		for (int i = 0; i < size; i++) {
			ret[i] = nextDouble();
		}

		return ret;
	}

	String nextLine() throws IOException {
		st = new StringTokenizer("");

		return in.readLine();
	}

	boolean isEof() throws IOException {
		while (!st.hasMoreTokens()) {
			String s = in.readLine();

			if (s == null) {
				return true;
			}

			st = new StringTokenizer(s);
		}

		return false;
	}

	void printRepeat(String s, int count) {
		for (int i = 0; i < count; i++) {
			out.print(s);
		}
	}

	void printArray(int[] array) {
		if (array == null || array.length == 0) {
			return;
		}

		for (int i = 0; i < array.length; i++) {
			if (i > 0) {
				out.print(' ');
			}

			out.print(array[i]);
		}

		out.println();
	}

	void printArray(long[] array) {
		if (array == null || array.length == 0) {
			return;
		}

		for (int i = 0; i < array.length; i++) {
			if (i > 0) {
				out.print(' ');
			}

			out.print(array[i]);
		}

		out.println();
	}

	void printArray(double[] array) {
		if (array == null || array.length == 0) {
			return;
		}

		for (int i = 0; i < array.length; i++) {
			if (i > 0) {
				out.print(' ');
			}

			out.print(array[i]);
		}

		out.println();
	}

	void printArray(double[] array, String spec) {
		if (array == null || array.length == 0) {
			return;
		}

		for (int i = 0; i < array.length; i++) {
			if (i > 0) {
				out.print(' ');
			}

			out.printf(Locale.US, spec, array[i]);
		}

		out.println();
	}

	void printArray(Object[] array) {
		if (array == null || array.length == 0) {
			return;
		}

		boolean blank = false;

		for (Object x : array) {
			if (blank) {
				out.print(' ');
			} else {
				blank = true;
			}

			out.print(x);
		}

		out.println();
	}

	@SuppressWarnings("rawtypes")
	void printCollection(Collection collection) {
		if (collection == null || collection.isEmpty()) {
			return;
		}

		boolean blank = false;

		for (Object x : collection) {
			if (blank) {
				out.print(' ');
			} else {
				blank = true;
			}

			out.print(x);
		}

		out.println();
	}

	static void swap(int[] a, int i, int j) {
		int tmp = a[i];
		a[i] = a[j];
		a[j] = tmp;
	}

	static void swap(long[] a, int i, int j) {
		long tmp = a[i];
		a[i] = a[j];
		a[j] = tmp;
	}

	static void swap(double[] a, int i, int j) {
		double tmp = a[i];
		a[i] = a[j];
		a[j] = tmp;
	}

	static void shuffle(int[] a, int from, int to) {
		for (int i = from; i < to; i++) {
			swap(a, i, RND.nextInt(a.length));
		}
	}

	static void shuffle(long[] a, int from, int to) {
		for (int i = from; i < to; i++) {
			swap(a, i, RND.nextInt(a.length));
		}
	}

	static void shuffle(double[] a, int from, int to) {
		for (int i = from; i < to; i++) {
			swap(a, i, RND.nextInt(a.length));
		}
	}

	static void shuffle(int[] a) {
		if (a == null) {
			return;
		}

		shuffle(a, 0, a.length);
	}

	static void shuffle(long[] a) {
		if (a == null) {
			return;
		}

		shuffle(a, 0, a.length);
	}

	static void shuffle(double[] a) {
		if (a == null) {
			return;
		}

		shuffle(a, 0, a.length);
	}

	static long[] getPartialSums(int[] a) {
		long[] sums = new long[a.length + 1];

		for (int i = 0; i < a.length; i++) {
			sums[i + 1] = sums[i] + a[i];
		}

		return sums;
	}

	static long[] getPartialSums(long[] a) {
		long[] sums = new long[a.length + 1];

		for (int i = 0; i < a.length; i++) {
			sums[i + 1] = sums[i] + a[i];
		}

		return sums;
	}

	static int[] getOrderedSet(int[] a) {
		int[] set = Arrays.copyOf(a, a.length);

		if (a.length == 0) {
			return set;
		}

		shuffle(set);
		Arrays.sort(set);
		int k = 1;
		int prev = set[0];

		for (int i = 1; i < a.length; i++) {
			if (prev != set[i]) {
				set[k++] = prev = set[i];
			}
		}

		return Arrays.copyOf(set, k);
	}

	static long[] getOrderedSet(long[] a) {
		long[] set = Arrays.copyOf(a, a.length);

		if (a.length == 0) {
			return set;
		}

		shuffle(set);
		Arrays.sort(set);
		int k = 1;
		long prev = set[0];

		for (int i = 1; i < a.length; i++) {
			if (prev != set[i]) {
				set[k++] = prev = set[i];
			}
		}

		return Arrays.copyOf(set, k);
	}

	static int gcd(int x, int y) {
		x = Math.abs(x);
		y = Math.abs(y);

		while (x > 0 && y > 0) {
			if (x > y) {
				x %= y;
			} else {
				y %= x;
			}
		}

		return x + y;
	}

	static long gcd(long x, long y) {
		x = Math.abs(x);
		y = Math.abs(y);

		while (x > 0 && y > 0) {
			if (x > y) {
				x %= y;
			} else {
				y %= x;
			}
		}

		return x + y;
	}
}








In   Python3   :






s = input()

prevs = dict()
a = []
for i in range(len(s)):
    if s[i] in prevs:
        a.append(i - prevs[s[i]])
    else:
        a.append(i + 1)
    prevs[s[i]] = i

class Node:
    def __init__(self, **d):
        self.__dict__ = d

class Edge:
    def __init__(self, **d):
        self.__dict__ = d

root = Node(edges = dict(), depth = 0, slink = None)
edge0 = Edge(a = root, b = root, u = 0, l = 0)
cur = (edge0, 0, 0)
leaves = 0
ans = 0

def conv(c, depth):
    return -1 if c > depth else c

def simplify(cur):
    edge, u, l = cur
    while l > edge.l:
        c = conv(a[u + edge.l], edge.a.depth + edge.l)
        edge, u, l = edge.b.edges[c], u + edge.l, l - edge.l
    return edge, u, l

def toStr(a, depth):
    l = []
    for i in range(len(a)):
        l.append(conv(a[i], depth + i))
    return map(str, l)

def printTree(edge, tabs = ''):
    print(tabs + ':'.join(toStr(a[edge.u:edge.u+edge.l], edge.a.depth)), 
    edge.b.depth, edge.b.slink)
    for e in edge.b.edges.values():
        printTree(e, tabs + '  ')

def slink(cur):
    edge, u, l = cur
    if edge.a == root:
        assert(edge != edge0)
        return simplify((edge0, u + 1, l - 1))
    else:
        edge.a.slink = simplify(edge.a.slink)
        e1, u1, l1 = edge.a.slink
        return simplify((e1, u - l1, l + l1))

#print(':'.join(map(str, a)))

for i in range(len(s)):
    while True:
        edge, u, l = cur
        c = conv(a[i], edge.a.depth + l)
        if l == edge.l:
            if c in edge.b.edges:
                break
            leaves += 1
            leaf = Node(depth = -1, slink = None, edges = dict())
            edge.b.edges[c] = Edge(a = edge.b, b = leaf, u = i, l = len(s) - i)
        else:
            c1 = conv(a[edge.u + l], edge.a.depth + l)
            if c == c1:
                break
            leaves += 1
            leaf = Node(depth = -1, slink = None, edges = dict())
            branch = Node(edges = dict(), depth = edge.a.depth + l, slink = slink(cur))
            branch.edges[c] = Edge(a = branch, b = leaf, u = i, l = len(s) - i)
            branch.edges[c1] = Edge(a = branch, b = edge.b, u = edge.u + l, l = edge.l - l)
            edge.b = branch
            edge.l = l
        if edge == edge0 and l == 0:
            cur = None
            break
        if edge.a == root:
            assert(edge != edge0)
            cur = simplify((edge0, u + 1, l - 1))
        else:
            edge.a.slink = simplify(edge.a.slink)
            e1, u1, l1 = edge.a.slink
            cur = simplify((e1, u - l1, l + l1))
    if cur == None:
        cur = edge0, i + 1, 0
    else:
        edge, u, l = cur
        assert(u + l == i)
        cur = simplify((edge, u, l + 1))
    ans += leaves
    print(ans)
    #printTree(edge0)
                        








View More Similar Problems

Tree Coordinates

We consider metric space to be a pair, , where is a set and such that the following conditions hold: where is the distance between points and . Let's define the product of two metric spaces, , to be such that: , where , . So, it follows logically that is also a metric space. We then define squared metric space, , to be the product of a metric space multiplied with itself: . For

View Solution →

Array Pairs

Consider an array of n integers, A = [ a1, a2, . . . . an] . Find and print the total number of (i , j) pairs such that ai * aj <= max(ai, ai+1, . . . aj) where i < j. Input Format The first line contains an integer, n , denoting the number of elements in the array. The second line consists of n space-separated integers describing the respective values of a1, a2 , . . . an .

View Solution →

Self Balancing Tree

An AVL tree (Georgy Adelson-Velsky and Landis' tree, named after the inventors) is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. We define balance factor for each node as : balanceFactor = height(left subtree) - height(righ

View Solution →

Array and simple queries

Given two numbers N and M. N indicates the number of elements in the array A[](1-indexed) and M indicates number of queries. You need to perform two types of queries on the array A[] . You are given queries. Queries can be of two types, type 1 and type 2. Type 1 queries are represented as 1 i j : Modify the given array by removing elements from i to j and adding them to the front. Ty

View Solution →

Median Updates

The median M of numbers is defined as the middle number after sorting them in order if M is odd. Or it is the average of the middle two numbers if M is even. You start with an empty number list. Then, you can add numbers to the list, or remove existing numbers from it. After each add or remove operation, output the median. Input: The first line is an integer, N , that indicates the number o

View Solution →

Maximum Element

You have an empty sequence, and you will be given N queries. Each query is one of these three types: 1 x -Push the element x into the stack. 2 -Delete the element present at the top of the stack. 3 -Print the maximum element in the stack. Input Format The first line of input contains an integer, N . The next N lines each contain an above mentioned query. (It is guaranteed that each

View Solution →