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

Fibonacci Numbers Tree

Shashank loves trees and math. He has a rooted tree, T , consisting of N nodes uniquely labeled with integers in the inclusive range [1 , N ]. The node labeled as 1 is the root node of tree , and each node in is associated with some positive integer value (all values are initially ). Let's define Fk as the Kth Fibonacci number. Shashank wants to perform 22 types of operations over his tree, T

View Solution →

Pair Sums

Given an array, we define its value to be the value obtained by following these instructions: Write down all pairs of numbers from this array. Compute the product of each pair. Find the sum of all the products. For example, for a given array, for a given array [7,2 ,-1 ,2 ] Note that ( 7 , 2 ) is listed twice, one for each occurrence of 2. Given an array of integers, find the largest v

View Solution →

Lazy White Falcon

White Falcon just solved the data structure problem below using heavy-light decomposition. Can you help her find a new solution that doesn't require implementing any fancy techniques? There are 2 types of query operations that can be performed on a tree: 1 u x: Assign x as the value of node u. 2 u v: Print the sum of the node values in the unique path from node u to node v. Given a tree wi

View Solution →

Ticket to Ride

Simon received the board game Ticket to Ride as a birthday present. After playing it with his friends, he decides to come up with a strategy for the game. There are n cities on the map and n - 1 road plans. Each road plan consists of the following: Two cities which can be directly connected by a road. The length of the proposed road. The entire road plan is designed in such a way that if o

View Solution →

Heavy Light White Falcon

Our lazy white falcon finally decided to learn heavy-light decomposition. Her teacher gave an assignment for her to practice this new technique. Please help her by solving this problem. You are given a tree with N nodes and each node's value is initially 0. The problem asks you to operate the following two types of queries: "1 u x" assign x to the value of the node . "2 u v" print the maxim

View Solution →

Number Game on a Tree

Andy and Lily love playing games with numbers and trees. Today they have a tree consisting of n nodes and n -1 edges. Each edge i has an integer weight, wi. Before the game starts, Andy chooses an unordered pair of distinct nodes, ( u , v ), and uses all the edge weights present on the unique path from node u to node v to construct a list of numbers. For example, in the diagram below, Andy

View Solution →