There are some websites that are accessible through several different addresses. For example, for a long time Codeforces was accessible with two hostnames codeforces.com and codeforces.ru.

You are given a list of page addresses being queried. For simplicity we consider all addresses to have the form http://<hostname>[/<path>], where:

  <hostname> — server name (consists of words and maybe some dots separating them),  /<path> — optional part, where <path> consists of words separated by slashes. 

We consider two <hostname> to correspond to one website if for each query to the first <hostname> there will be exactly the same query to the second one and vice versa — for each query to the second <hostname> there will be the same query to the first one. Take a look at the samples for further clarifications.

Your goal is to determine the groups of server names that correspond to one website. Ignore groups consisting of the only server name.

Please note, that according to the above definition queries http://<hostname> and http://<hostname>/ are different.


-----Input-----

The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of page queries. Then follow n lines each containing exactly one address. Each address is of the form http://<hostname>[/<path>], where:

  <hostname> consists of lowercase English letters and dots, there are no two consecutive dots, <hostname> doesn't start or finish with a dot. The length of <hostname> is positive and doesn't exceed 20.  <path> consists of lowercase English letters, dots and slashes. There are no two consecutive slashes, <path> doesn't start with a slash and its length doesn't exceed 20. 

Addresses are not guaranteed to be distinct.


-----Output-----

First print k — the number of groups of server names that correspond to one website. You should count only groups of size greater than one.

Next k lines should contain the description of groups, one group per line. For each group print all server names separated by a single space. You are allowed to print both groups and names inside any group in arbitrary order.


-----Examples-----
Input
10
http://abacaba.ru/test
http://abacaba.ru/
http://abacaba.com
http://abacaba.com/test
http://abacaba.de/
http://abacaba.ru/test
http://abacaba.de/test
http://abacaba.com/
http://abacaba.com/t
http://abacaba.com/test

Output
1
http://abacaba.de http://abacaba.ru 

Input
14
http://c
http://ccc.bbbb/aba..b
http://cba.com
http://a.c/aba..b/a
http://abc/
http://a.c/
http://ccc.bbbb
http://ab.ac.bc.aa/
http://a.a.a/
http://ccc.bbbb/
http://cba.com/
http://cba.com/aba..b
http://a.a.a/aba..b/a
http://abc/aba..b/a

Output
2
http://cba.com http://ccc.bbbb 
http://a.a.a http://a.c http://abc

Source: codeforces | Difficulty: HARD
Tags: String algorithms

Sorting

Data structures

Implementation


Solutions:
import sys
d = dict()
b = '/'
for line in sys.stdin:
	line = line[:-1].split(b)
	(host, coso) = (b.join(line[:3]), b.join(line[3:]))
	if len(line) > 3:
		coso = '/' + coso
	if len(line) > 1:
		if host in d:
			d[host].append('I' + coso)
		else:
			d[host] = ['I' + coso]
for host in d:
	b = ','
	d[host] = sorted(set(d[host]))
	d[host] = b.join(d[host])
d2 = dict()
for host in d:
	if d[host] in d2:
		d2[d[host]].append(host)
	else:
		d2[d[host]] = [host]
print(sum([len(d2[x]) > 1 for x in d2]))
for x in d2:
	if len(d2[x]) > 1:
		for i in d2[x]:
			sys.stdout.write(i + ' ')
		sys.stdout.write('\n')


P = 910519
MOD = 32416190071
p = [1]
for i in range(1, 200010):
	p.append(P * p[i - 1] % MOD)
n = int(input())
s = list(set([input() for i in range(n)]))
n = len(s)
name = ['' for i in range(n)]
path = ['' for i in range(n)]
mp = {}
for i in range(n):
	link = s[i]
	j = link[7:].find('/')
	if j != -1:
		path[i] = link[j + 7:]
		name[i] = link[:j + 7]
	else:
		name[i] = link
for i in range(n):
	if path[i] not in mp:
		mp[path[i]] = len(mp)
h = {name[i]: 0 for i in range(n)}
for i in range(n):
	h[name[i]] += p[mp[path[i]]]
gp = {}
for (key, val) in h.items():
	if val in gp:
		gp[val].append(key)
	else:
		gp[val] = [key]
ans = []
for (key, val) in gp.items():
	if len(val) > 1:
		ans.append(val)
print(len(ans))
for a in ans:
	print(' '.join(a))


n = int(input())
d = {}
D = {}
ans = []
for _ in range(n):
	s = input() + '/'
	t = s.find('/', 7)
	d.setdefault(s[:t], set()).add(s[t:])
for k in d:
	D.setdefault(frozenset(d[k]), []).append(k)
{ans.append(D[k]) for k in D if len(D[k]) > 1}
print(len(ans))
print('\n'.join(map(' '.join, ans)))


n = int(input())
d = {}
D = {}
for i in range(n):
	(h, *p) = (input()[7:] + '/').split('/')
	d.setdefault(h, set()).add('/'.join(p))
for x in d:
	D.setdefault(frozenset(d[x]), []).append(x)

def ans():
	for x in D:
		if len(D[x]) > 1:
			yield ('http://' + ' http://'.join(D[x]))
print(sum((1 for x in D if len(D[x]) > 1)))
print('\n'.join(ans()))


import sys
from collections import defaultdict
n = int(sys.stdin.readline())
h = defaultdict(set)
for iter in range(n):
	entry = sys.stdin.readline().rstrip() + '/'
	path_start = 7 + entry[7:].index('/')
	hostname = entry[:path_start]
	path = entry[path_start:]
	h[hostname].add(path)
res = defaultdict(list)
for (k, v) in h.items():
	res[frozenset(v)].append(k)
output = []
for v in res.values():
	if len(v) > 1:
		output.append(' '.join(v))
print(len(output))
for u in output:
	print(u)


import sys
n = int(input())
domains = {}
for full_request in sys.stdin:
	request = full_request[7:-1]
	(domain, sep, path) = request.partition('/')
	if domain in domains:
		domains[domain].add(sep + path)
	else:
		domains[domain] = {sep + path}
path_hashes = []
for (domain, paths) in list(domains.items()):
	path_hashes.append(('|'.join(sorted(paths)), domain))
sorted_hashes = sorted(path_hashes, key=lambda x: x[0])
previous_hash = None
previous_domains = []
groups = []
for (path_hash, domain) in sorted_hashes:
	if previous_hash == path_hash:
		previous_domains.append(domain)
	else:
		previous_hash = path_hash
		if len(previous_domains) > 1:
			groups.append(previous_domains)
		previous_domains = [domain]
if len(previous_domains) > 1:
	groups.append(previous_domains)
print(len(groups))
print('\n'.join([' '.join(['http://' + y for y in x]) for x in groups]))


import sys
from urllib.parse import urlparse
import itertools as itt

def main():
	n = int(sys.stdin.readline().strip())
	links = [sys.stdin.readline().strip() for i in range(n)]
	host_queries = {}
	for link in links:
		p = urlparse(link)
		host = 'http://' + p.netloc
		query = p.path
		if not host in host_queries:
			host_queries[host] = set()
		host_queries[host].add(query)
	hosts = host_queries.keys()
	hosts = list(sorted(hosts, key=lambda h: '-'.join(sorted(host_queries[h]))))
	groups = []
	for (key, group) in itt.groupby(hosts, key=lambda h: '-'.join(sorted(host_queries[h]))):
		g = list(group)
		if len(g) < 2:
			continue
		groups.append(g)
	print(len(groups))
	for g in groups:
		print(' '.join(g))
main()


n = int(input())
d = dict()
for i in range(n):
	s = input().strip()
	s = s[7:]
	f = s.find('/')
	if f != -1:
		a = s[:f]
		b = s[f:]
	else:
		a = s
		b = ''
	if a in d:
		d[a].add(b)
	else:
		d[a] = {b}
ans = dict()
for i in d:
	x = sorted(d[i])
	x = list(x)
	x = '*'.join(x)
	d[i] = x
	if x in ans:
		ans[x].append(i)
	else:
		ans[x] = [i]
ans2 = []
ansc = 0
for i in ans:
	if len(ans[i]) > 1:
		ansc += 1
		ans2.append(' '.join(map(lambda x: 'http://' + x, ans[i])))
print(ansc)
for i in ans2:
	print(i)


n = int(input())
W = {}
for i in range(n):
	adr = input()
	adr = adr.split('/')
	if adr[-1] == '':
		adr[-1] = '?'
	domena = '/'.join(adr[:3])
	adres = '/'.join(adr[3:])
	if domena not in W:
		W[domena] = set()
	W[domena].add(adres)
E = {}
for (key, ele) in list(W.items()):
	lele = '#'.join(sorted(list(ele)))
	if lele not in E:
		E[lele] = []
	E[lele].append(key)
res = 0
for (key, ele) in list(E.items()):
	if len(ele) > 1:
		res += 1
print(res)
for (key, ele) in list(E.items()):
	if len(ele) > 1:
		print(' '.join(ele))


from sys import stdin, stdout
from collections import defaultdict
from re import compile, match
n = int(input())
b = defaultdict(set)
pattern = compile('(?P<domain>http://[a-zA-Z0-9.]*)(?P<adress>.*)')
for name in stdin.readlines():
	if not name[-1] == '/':
		name += '/'
	m = pattern.match(name)
	b[m.group('domain')].add(m.group('adress'))
k = defaultdict(set)
num = 0
for (domain, adress) in b.items():
	k[frozenset(adress)].add(domain)
ans = []
for group in k.values():
	if len(group) > 1:
		ans.append(' '.join((i for i in group)) + '\n')
print(len(ans))
stdout.writelines(ans)


from sys import stdin
from collections import defaultdict

def main():
	(s, d) = (input(), defaultdict(set))
	for s in stdin.read().splitlines():
		i = s.find('/', 8)
		if i == -1:
			d[s].add('')
		else:
			d[s[:i]].add(s[i:])
	e = defaultdict(list)
	for (s, v) in d.items():
		e[' '.join(sorted(v))].append(s)
	r = [' '.join(v) for v in e.values() if len(v) > 1]
	print(len(r))
	print('\n'.join(r))
main()


import functools
import itertools
import operator

def split(address):
	address = address[7:]
	p = address.find('/')
	if p == -1:
		return (address, '')
	return (address[:p], address[p:])

def set_key(addr1, addr2):
	(pages1, pages2) = (addr1[1], addr2[1])
	l1 = len(pages1)
	l2 = len(pages2)
	if l1 != l2:
		return l2 - l1
	for (page1, page2) in zip(pages1, pages2):
		if page1 < page2:
			return -1
		if page1 > page2:
			return 1
	return 0

def solve(addresses):
	addresses = list(map(split, addresses))
	m = dict()
	for (domain, page) in addresses:
		if domain in m:
			m[domain].add(page)
		else:
			m[domain] = {page}
	l = [(domain, sorted(pages)) for (domain, pages) in m.items()]
	l.sort(key=functools.cmp_to_key(set_key))
	groups = []
	gb = itertools.groupby(l, key=operator.itemgetter(1))
	for (key, group) in gb:
		group_domains = ['http://' + d for (d, ps) in group]
		if len(group_domains) > 1:
			groups.append(group_domains)
	return groups

def main():
	n = int(input())
	addresses = [None] * n
	for i in range(n):
		addresses[i] = input()
	groups = solve(addresses)
	print(len(groups))
	for group in groups:
		print(' '.join(group))

def test():
	import random
	import string
	n = 100000
	addresses = []
	for i in range(n):
		domain = ''.join([random.choice(string.ascii_lowercase) for dummy in range(5)])
		page = ''.join([random.choice(string.ascii_lowercase) for dummy in range(5)])
		addresses.append('http://{}/{}'.format(domain, page))
	print('Solving...')
	s = solve(addresses)
	print(s)
main()


from itertools import groupby
web_addresses_number = int(input())
prephix = 'http://'

def split_address(address):
	host = ''
	path = ''
	address = address[7:]
	i = 0
	while i < len(address) and address[i] != '/':
		host += address[i]
		i += 1
	while i < len(address):
		path += address[i]
		i += 1
	return (host, path)
hosts = {}
for i in range(web_addresses_number):
	(host, path) = split_address(input())
	if host in hosts:
		hosts[host].add(path)
	else:
		hosts[host] = {path}
groups = []
hosts = {host: '+'.join(sorted(hosts[host])) for host in hosts}
groping = groupby(sorted(hosts, key=lambda host: hosts[host]), key=lambda host: hosts[host])
for (key, group) in groping:
	g = list(group)
	if len(g) > 1:
		groups.append(g)
print(len(groups))
[print(' '.join(map(lambda host: prephix + host, group))) for group in groups]


n = int(input())
domains = {}
for _ in range(n):
	request = input()[7:]
	(domain, sep, path) = request.partition('/')
	if domain in domains:
		domains[domain].add(sep + path)
	else:
		domains[domain] = {sep + path}
path_hashes = []
for (domain, paths) in domains.items():
	path_hashes.append(('|'.join(sorted(paths)), domain))
sorted_hashes = sorted(path_hashes, key=lambda x: x[0])
previous_hash = None
previous_domains = []
groups = []
for (path_hash, domain) in sorted_hashes:
	if previous_hash == path_hash:
		previous_domains.append(domain)
	else:
		previous_hash = path_hash
		if len(previous_domains) > 1:
			groups.append(previous_domains)
		previous_domains = [domain]
if len(previous_domains) > 1:
	groups.append(previous_domains)
print(len(groups))
print('\n'.join(map(lambda x: ' '.join(map(lambda y: 'http://' + y, x)), groups)))


n = int(input())
d = dict()
for _ in range(n):
	s = input()
	slash = s.find('/', 7)
	if slash == -1:
		slash = len(s)
	host = s[:slash]
	query = s[slash:]
	d.setdefault(host, set()).add(query)
d1 = dict()
for (k, v) in d.items():
	f = frozenset(v)
	d1.setdefault(f, set()).add(k)
res = {k: v for (k, v) in d1.items() if len(v) > 1}
print(len(res))
for block in res.values():
	print(' '.join(block))


n = int(input())
hosts = dict()
for i in range(n):
	inp = input()
	pos = inp.find('/', 7)
	if pos == -1:
		pos = len(inp)
	hostName = inp[:pos]
	path = inp[pos:]
	if hostName not in hosts:
		hosts[hostName] = set()
	hosts[hostName].add(path)
groups = dict()
for name in hosts.keys():
	paths = tuple(sorted(hosts[name]))
	if paths not in groups:
		groups[paths] = []
	groups[paths].append(name)
ans = []
for group in groups.values():
	if len(group) > 1:
		ans.append(group)
print(len(ans))
for group in ans:
	print(' '.join(group))


import re
url_parser = re.compile('^http://([^/]+)(.*)')
while True:
	try:
		k = int(input())
	except EOFError:
		break
	d = {}
	for _ in range(k):
		(hostname, path) = url_parser.findall(input())[0]
		if hostname in d:
			d[hostname].add(path)
		else:
			d[hostname] = set((path,))
	d_reverse = {}
	for (hostname, pathset) in d.items():
		thumb = '_'.join(sorted(pathset))
		if thumb in d_reverse:
			d_reverse[thumb].append(hostname)
		else:
			d_reverse[thumb] = [hostname]
	ans = [line for line in d_reverse.values() if len(line) > 1]
	print(len(ans))
	for line in ans:
		print(' '.join(map(lambda x: 'http://' + x, line)))