Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// Mo's Algorithm On Trees
- #define LOG 18
- #define MAX 100010
- #define MAXQ 100010
- /// SPOJ Count On A Tree II, Number of distinct values on nodes on the path from U to V
- namespace mo{ /// Mo's Algorithm on Trees, 0-based index
- int q, counter, block_size = 337, out[MAXQ], freq[MAX]; /// block_size = sqrt(2*N)
- struct Query{
- int l, r, s, d, idx;
- inline Query() {}
- inline Query(int a, int b, int p, int c){
- idx = c;
- l = a, r = b, s = p, d = l / block_size;
- }
- inline bool operator < (const Query& other) const{
- if (d != other.d) return (d < other.d);
- return ((d & 1) ? (r < other.r) : (r > other.r));
- }
- } Q[MAXQ];
- vector <int> adj[MAX];
- int n, r, t, S[MAX], E[MAX], ar[MAX << 1], parent[MAX], depth[MAX], lg[MAX], nodeval[MAX], nodecount[MAX], dp[MAX][LOG];
- void init(int nodes, int root, int sz, int* nodevalT){ /// Values on nodes, modify appropriately if values on edges
- lg[0] = lg[1] = 0;
- block_size = max(1, sz);
- clr(freq), clr(nodecount);
- q = 0, t = 0, n = nodes, r = root;
- for (int i = 0; i <= n; i++) adj[i].clear();
- for (int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
- for (int i = 0; i < n; i++) nodeval[i] = nodevalT[i];
- }
- inline void add_edge(int u, int v){
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
- inline int lca(int a, int b){
- if (a == b) return a;
- if (depth[a] < depth[b]) swap(a, b);
- for (int i = lg[depth[a] - depth[b]]; i >= 0; i--){
- if ((depth[a] - (1 << i)) >= depth[b]) a = dp[a][i];
- }
- if (a == b) return a;
- for (int i = lg[depth[a]]; i >= 0; i--){
- if (dp[a][i] != dp[b][i]){
- a = dp[a][i];
- b = dp[b][i];
- }
- }
- return (a == b) ? a : parent[a];
- }
- inline void dfs(int i, int p){
- S[i] = t, ar[t++] = i;
- int j, len = adj[i].size();
- for (j = 0, parent[i] = p; j < len; j++){
- if (adj[i][j] != p){
- depth[adj[i][j]] = depth[i] + 1;
- dfs(adj[i][j], i);
- }
- }
- E[i] = t, ar[t++] = i;
- }
- inline void build(){
- depth[r] = 0;
- dfs(r, r);
- for (int l = 0; l <= lg[n]; l++){
- for (int i = 0; i < n; i++){
- if (!l) dp[i][l] = parent[i];
- else dp[i][l] = dp[dp[i][l - 1]][l - 1];
- }
- }
- }
- inline void push(int a, int b, int idx){
- if (depth[a] > depth[b]) swap(a, b);
- int l = lca(a, b);
- if (a == l) Q[q++] = Query(S[a], S[b], -1, idx);
- else{
- if (E[b] <= S[a]) Q[q++] = Query(E[b], S[a], S[l], idx);
- else Q[q++] = Query(E[a], S[b], S[l], idx);
- }
- }
- /// If a node occurs twice in a range, then both its value needs to be ignored
- inline void insert(int idx){
- int x = ar[idx];
- if (nodecount[x]){
- freq[nodeval[x]]--;
- if (freq[nodeval[x]] == 0) counter--;
- }
- else{
- if (freq[nodeval[x]] == 0) counter++;
- freq[nodeval[x]]++;
- }
- nodecount[x] ^= 1;
- }
- inline void erase(int idx){
- int x = ar[idx];
- if (!nodecount[x]){
- if (freq[nodeval[x]] == 0) counter++;
- freq[nodeval[x]]++;
- }
- else{
- freq[nodeval[x]]--;
- if (freq[nodeval[x]] == 0) counter--;
- }
- nodecount[x] ^= 1;
- }
- inline void run(){
- counter = 0;
- sort(Q, Q + q);
- int i, l, r, a = 0, b = 0; /// Change here if 1-based array
- for (i = 0; i < q; i++){
- l = Q[i].l, r = Q[i].r;
- while (a > l) insert(--a);
- while (b <= r) insert(b++);
- while (a < l) erase(a++);
- while (b > (r + 1)) erase(--b);
- if (Q[i].s != -1) insert(Q[i].s);
- out[Q[i].idx] = counter;
- if (Q[i].s != -1) erase(Q[i].s);
- }
- }
- inline void print(){
- for (int i = 0; i < q; i++) printf("%d\n", out[i]);
- }
- }
- int T[MAX], H[MAX];
- tr1::unordered_map <int, int> mp;
- int main(){
- int n, q, h, i, j, k, a, b;
- scanf("%d %d", &n, &q);
- for (i = 0; i < n; i++) scanf("%d", &T[i]);
- /// Co-ordinate compression, necessary only for this problem
- /*** mp.clear();
- for (h = 0, i = 0; i < n; i++) H[i] = T[i];
- sort(H, H + n);
- H[n] = -1;
- for (i = 0; i < n; i++){
- if (H[i] != H[i + 1]) mp[H[i]] = ++h;
- }
- for (i = 0; i < n; i++) T[i] = mp[T[i]]; ***/
- mo::init(n, 0, 337, T);
- for (i = 1; i < n; i++){
- scanf("%d %d", &a, &b);
- a--, b--;
- mo::add_edge(a, b);
- }
- mo::build();
- for (i = 0; i < q; i++) {
- scanf("%d %d", &a, &b);
- a--, b--;
- mo::push(a, b, i);
- }
- mo::run();
- mo::print();
- return 0;
- }
- /// MO's algo
- #define MAXN 200010
- #define MAXQ 200010
- #define MAXV 1000010
- /// 0 based index for arrays and queries
- const int block_size = 633;
- long long res, out[MAXQ];
- int n, q, ar[MAXN], freq[MAXV];
- struct query{
- int l, r, d, i;
- inline query() {}
- inline query(int a, int b, int c){
- i = c;
- l = a, r = b, d = l / block_size;
- }
- inline bool operator < (const query& other) const{
- if (d != other.d) return (d < other.d);
- return ((d & 1) ? (r < other.r) : (r > other.r));
- }
- } Q[MAXQ];
- inline void insert(int i){
- res += (long long)ar[i] * (1 + 2 * freq[ar[i]]++);
- }
- inline void erase(int i){
- res -= (long long)ar[i] * (1 + 2 * --freq[ar[i]]);
- }
- inline void run(){ /// hash = 812195
- sort(Q, Q + q);
- int i, l, r, a = 0, b = 0;
- for (res = 0, i = 0; i < q; i++){
- l = Q[i].l, r = Q[i].r;
- while (a > l) insert(--a);
- while (b <= r) insert(b++);
- while (a < l) erase(a++);
- while (b > (r + 1)) erase(--b);
- out[Q[i].i] = res;
- }
- for (i = 0; i < q; i++) printf("%lld\n", out[i]);
- }
- int main(){
- int n, i, j, k, a, b;
- scanf("%d %d", &n, &q);
- for (i = 0; i < n; i++) scanf("%d", &ar[i]);
- for (i = 0; i < q; i++){
- scanf("%d %d", &a, &b);
- Q[i] = query(a - 1, b - 1, i);
- }
- run();
- return 0;
- }
- /// Radix Sort
- #define CHUNK 8
- #define MAX 1000010
- int n;
- unsigned int bucket[1 << CHUNK], ar[MAX + 10], temp[MAX + 10];
- void radix_sort(unsigned int* ar, int n){
- int i, j, x;
- const int bitmask = (1 << CHUNK) - 1;
- for (i = 0; i < 32; i += CHUNK){
- clr(bucket);
- for (j = 0; j < n; j++) bucket[(ar[j] >> i) & bitmask]++;
- for (j = 1; j <= bitmask; j++){
- bucket[j] += bucket[j - 1];
- }
- for (j = n - 1; j >= 0; j--) temp[--bucket[(ar[j] >> i) & bitmask]] = ar[j];
- for (j = 0; j < n; j++) ar[j] = temp[j];
- }
- }
- int main(){
- n = MAX;
- srand(time(0));
- int i, j, k, x, y;
- for (i = 0; i < n; i++) ar[i] = (rand() * rand());
- clock_t start = clock();
- radix_sort(ar, n);
- for (i = 0; (i + 1) < n; i++){
- if (ar[i] > ar[i + 1]) puts("YO");
- }
- printf("%0.5f s\n", (clock() - start) / (1.0 * CLOCKS_PER_SEC));
- return 0;
- }
- /// Treap (Static)
- #define MAXN 200010
- struct node{
- node *l, *r;
- int key, subtree, priority;
- inline node(){
- l = r = 0;
- }
- inline node(int val){
- l = r = 0;
- subtree = 1, key = val;
- priority = (rand() << 16) ^ rand();
- }
- inline void update(){
- subtree = 1;
- if (l) subtree += l->subtree;
- if (r) subtree += r->subtree;
- }
- } pool[MAXN]; /// Maximum number of nodes in treap
- struct Treap{
- int idx; /// Make global if multiple copy of treaps required as of some moment
- struct node* root;
- inline void merge(node* &cur, node* l, node* r){
- if (!l || !r) cur = l ? l : r;
- else if (l->priority > r->priority) merge(l->r, l->r, r), cur = l;
- else merge(r->l, l, r->l), cur = r;
- if (cur) cur->update();
- }
- /// Splits treap into 2 treaps l and r such that all values in l <= key and all values in r > key
- inline void split(node* cur, node* &l, node* &r, int key){
- if (!cur) l = r = 0;
- else if (key <= cur->key) split(cur->l, l, cur->l, key), r = cur;
- else split(cur->r, cur->r, r, key), l = cur;
- if (cur) cur->update();
- }
- inline void insert(node* &cur, node* it){
- if (!cur) cur = it;
- else if (it->priority > cur->priority) split(cur, it->l, it->r, it->key), cur = it;
- else insert((it->key < cur->key)? cur->l : cur->r, it);
- if (cur) cur->update();
- }
- inline void erase(node* &cur, int key){
- if (!cur) return;
- if (cur->key == key) merge(cur, cur->l, cur->r);
- else erase((cur->key > key) ? cur->l : cur->r, key);
- if (cur) cur->update();
- }
- Treap(){
- srand(time(0));
- idx = 0, root = 0; /// Remove idx = 0 and include in main to reset all
- /// if multiple copy of treaps required as of some moment
- }
- inline void insert(int key){
- pool[idx] = node(key);
- insert(root, &pool[idx++]);
- }
- inline void erase(int key){
- erase(root, key);
- }
- inline int size(){
- if (root) return root->subtree;
- return 0;
- }
- /// Returns the k'th smallest element of the treap in 1-based index, -1 on failure
- inline int kth(int k){
- if ((k < 1) || (k > size())) return -1;
- node *l, *r, *cur = root;
- for (; ;){
- l = cur->l, r = cur->r;
- if (l){
- if (k <= l->subtree) cur = l;
- else if ((l->subtree + 1) == k) return cur->key;
- else cur = r, k -= (l->subtree + 1);
- }
- else{
- if (k == 1) return (cur->key);
- else cur = r, k--;
- }
- }
- }
- /// Returns the count of keys less than x in the treap
- inline int count(int key){
- int res = 0;
- node *l, *r, *cur = root;
- while (cur){
- l = cur->l, r = cur->r;
- if (cur->key < key) res++;
- if (key < cur->key) cur = l;
- else{
- cur = r;
- if (l) res += l->subtree;
- }
- }
- return res;
- }
- };
- /// Treap With Implicit Keys (Run Length Encoding)
- #define MAXN 1000010
- struct node{
- node *l, *r;
- int val, counter, mask, subtree, priority;
- inline node(){
- l = r = 0;
- }
- inline node(int v, int c, int p){
- l = r = 0;
- priority = p;
- subtree = c, val = v, counter = c, mask = (1 << v);
- }
- inline node(int v, int c){
- node(v, c, (rand() << 16) ^ rand());
- }
- inline void update(){
- subtree = counter;
- if (l) subtree += l->subtree;
- if (r) subtree += r->subtree;
- }
- } pool[MAXN]; /// Maximum number of nodes in treap
- struct Treap{
- int idx;
- struct node* root;
- inline void join(node* cur){
- if (!cur) return;
- cur->update();
- cur->mask = 1 << cur->val;
- if (cur->l) cur->mask |= cur->l->mask;
- if (cur->r) cur->mask |= cur->r->mask;
- }
- inline void merge(node* &cur, node* l, node* r){
- if (!l || !r) cur = l ? l : r;
- else if (l->priority > r->priority) merge(l->r, l->r, r), cur = l;
- else merge(r->l, l, r->l), cur = r;
- if (cur) join(cur);
- }
- /// Smallest v such that l->subtree = v and v >= key
- inline void split(node* cur, node* &l, node* &r, int key, int counter = 0){
- if (!cur){
- l = r = 0;
- return;
- }
- int cur_key = counter + (cur->l ? cur->l->subtree : 0);
- if (key <= cur_key) split(cur->l, l, cur->l, key, counter), r = cur;
- else split(cur->r, cur->r, r, key, cur_key + cur->counter), l = cur;
- if (cur) join(cur);
- }
- inline void divide(node* &cur, int i){
- node *l, *r, *m, *t;
- split(cur, l, r, i);
- if (!(!l || l->subtree == i)){
- m = l;
- while (m->r) m = m->r;
- int v = m->val, c1 = i - (l->subtree - m->counter), c2 = m->counter - c1;
- split(l, l, t, l->subtree - m->counter);
- pool[idx] = node(v, c1);
- merge(l, l, &pool[idx++]); /// Assign to t or m if required
- pool[idx] = node(v, c2);
- merge(l, l, &pool[idx++]); /// Assign to t or m if required
- }
- merge(cur, l, r);
- }
- inline void insert(int i, int v, int c){ /// Inserts c copies of v after position i
- divide(root, i);
- node *l, *r, *m;
- split(root, l, r, i);
- pool[idx] = node(v, c);
- merge(l, l, &pool[idx++]);
- merge(root, l, r);
- }
- inline void erase(int a, int b){ /// Removes the segment [a:b]
- node *l, *r, *m;
- divide(root, a - 1);
- split(root, l, r, a - 1);
- divide(r, b - a + 1);
- split(r, m, r, b - a + 1);
- merge(root, l, r);
- }
- inline int query(int a, int b){ /// Number of distinct characters(a-z) in the segment [a:b]
- node *l, *r, *m;
- divide(root, a - 1);
- split(root, l, r, a - 1);
- divide(r, b - a + 1);
- split(r, m, r, b - a + 1);
- int res = m->mask;
- merge(l, l, m);
- merge(root, l, r);
- return __builtin_popcount(res);
- }
- Treap(){
- idx = 0, root = 0;
- }
- inline int size(){
- if (root) return root->subtree;
- return 0;
- }
- };
- /// Walsh-Hadamard Transformation
- #define MAX 1048576
- long long ar[MAX];
- void walsh_transform(long long* ar, int n){
- if (n == 0) return;
- int i, m = n / 2;
- walsh_transform(ar, m);
- walsh_transform(ar + m, m);
- for (i = 0; i < m; i++){
- long long x = ar[i], y = ar[i + m];
- ar[i] = x + y, ar[i + m] = x - y;
- }
- }
- void inverse_walsh_transform(long long* ar, int n){
- if (n == 0) return;
- int i, m = n / 2;
- inverse_walsh_transform(ar, m);
- inverse_walsh_transform(ar + m, m);
- for (i = 0; i < m; i++){
- long long x = ar[i], y = ar[i + m];
- ar[i] = (x + y) >> 1, ar[i + m] = (x - y) >> 1;
- }
- }
- int main(){
- int n, i, j, k, x;
- scanf("%d", &n);
- while (n--){
- scanf("%d", &x);
- ar[x]++;
- }
- walsh_transform(ar, MAX);
- for (i = 0; i < MAX; i++) ar[i] *= ar[i];
- inverse_walsh_transform(ar, MAX);
- long long res = 0;
- for (i = 0; i < MAX; i++) res += (ar[i] * i);
- printf("%lld\n", res / 2);
- return 0;
- }
- /// 3D fenwick tree
- #define MAX 205
- /// 3D Fenwick tree, Range updates and point queries
- struct Fenwick3D{
- int n, m, r, tree[MAX][MAX][MAX];
- Fenwick3D(){
- }
- Fenwick3D(int a, int b, int c){
- clr(tree);
- n = a, m = b, r = c;
- }
- /// Add v to the cube from lower-right [i,j,k] to upper-left [1,1,1]
- void update(int i, int j, int k, int v){
- if ((i < 0) || (j < 0) || (i > n) || (j > m) || (k < 0) || (k > r)) return;
- while (i){
- int x = j;
- while (x){
- int y = k;
- while (y){
- tree[i][x][y] += v;
- y ^= (y & (-y));
- }
- x ^= (x & (-x));
- }
- i ^= (i & (-i));
- }
- }
- /// Add v to the cube from upper-left [x1,y1,z1] to lower-right [x2,y2,z2]
- void update(int x1, int y1, int z1, int x2, int y2, int z2){
- update(x2, y2, z2, 1), update(x1 - 1, y1 - 1, z2, 1);
- update(x1 - 1, y2, z1 - 1, 1), update(x2, y1 - 1, z1 - 1, 1);
- update(x1 - 1, y2, z2, -1), update(x2, y1 - 1, z2, -1);
- update(x2, y2, z1 - 1, -1), update(x1 - 1, y1 - 1, z1 - 1, -1);
- }
- /// Query for the value at index [i][j][k]
- int query(int i, int j, int k){
- int res = 0;
- while (i <= n){
- int x = j;
- while (x <= m){
- int y = k;
- while (y <= r){
- res += tree[i][x][y];
- y += (y & (-y));
- }
- x += (x & (-x));
- }
- i += (i & (-i));
- }
- return res;
- }
- };
- /// 2D Fenwick tree
- #define MAX 1010
- /// 2D Fenwick tree, Point updates and range queries
- class Fenwick2D{
- public:
- int n, m, tree[MAX][MAX];
- Fenwick2D(){
- }
- Fenwick2D(int a, int b){
- clr(tree);
- n = a, m = b;
- }
- /// Add v to ar[i][j]
- void update(int i, int j, int v){
- while (i <= n){
- int k = j;
- while (k <= m){
- tree[i][k] += v;
- k += (k & (-k));
- }
- i += (i & (-i));
- }
- }
- /// Query for sum of the sub-rectangle from upper-left [i,j] to lower-right [n,n]
- int query(int i, int j){
- if ((i < 0) || (j < 0) || (i > n) || (j > m)) return 0;
- int res = 0;
- while (i){
- int k = j;
- while (k){
- res += tree[i][k];
- k ^= (k & (-k));
- }
- i ^= (i & (-i));
- }
- return res;
- }
- /// Query for sum of the sub-rectangle from upper-left [i,j] to lower-right [k,l]
- int query(int i, int j, int k, int l){
- if (i > k || j > l) return 0;
- int res = query(k, l) - query(i - 1, l) + query(i - 1, j - 1) - query(k, j - 1);
- return res;
- }
- };
- /// 2D Fenwick tree, Range updates and point queries
- class Fenwick2D{
- public:
- int n, m, tree[MAX][MAX];
- Fenwick2D(){
- }
- Fenwick2D(int a, int b){
- clr(tree);
- n = a, m = b;
- }
- /// Add v to the sub-rectangle from upper-left [i,j] to lower-right [n,n]
- void update(int i, int j, int v){
- if ((i < 0) || (j < 0) || (i > n) || (j > m)) return;
- while (i <= n){
- int k = j;
- while (k <= m){
- tree[i][k] += v;
- k += (k & (-k));
- }
- i += (i & (-i));
- }
- }
- /// Add v to the sub-rectangle from upper-left [i,j] to lower-right [k,l]
- void update(int i, int j, int k, int l, int v){
- if (i > k || j > l) return;
- update(i, j, v);
- update(k + 1, j, -v);
- update(k + 1, l + 1, v);
- update(i, l + 1, -v);
- }
- /// Query for the value at index [i][j]
- int query(int i, int j){
- int res = 0;
- while (i){
- int k = j;
- while (k){
- res += tree[i][k];
- k ^= (k & (-k));
- }
- i ^= (i & (-i));
- }
- return res;
- }
- };
- /// 2D Fenwick tree, Range updates and range queries
- class Fenwick2D{
- public:
- int n, m;
- long long tree[4][MAX][MAX];
- Fenwick2D(){
- }
- Fenwick2D(int a, int b){
- clr(tree);
- n = a, m = b;
- }
- /// Add v to the sub-rectangle from upper-left [p,q] to lower-right [n,n]
- void update(int p, int q, long long v){
- if ((p < 0) || (q < 0) || (p > n) || (q > m)) return;
- int i = p, c = p - 1, d = q - 1;
- while (i <= n){
- int j = q;
- while (j <= m){
- tree[0][i][j] += v;
- tree[1][i][j] += (v * d);
- tree[2][i][j] += (v * c);
- tree[3][i][j] += (v * c * d);
- j += (j & (-j));
- }
- i += (i & (-i));
- }
- }
- /// Query for sum of the sub-rectangle from upper-left [p,q] to lower-right [n,n]
- long long query(int p, int q){
- int i, j;
- long long x, y, z, c, d, res;
- i = p, x = y = z = 0;
- while (i){
- j = q, c = d = 0;
- while (j){
- c += tree[0][i][j];
- d += tree[1][i][j];
- y += tree[2][i][j];
- z += tree[3][i][j];
- j ^= (j & (-j));
- }
- i ^= (i & (-i));
- x += ((c * q) - d);
- }
- res = (x * p) - (y * q) + z;
- return res;
- }
- /// Add v to the sub-rectangle from upper-left [i,j] to lower-right [k,l]
- void update(int i, int j, int k, int l, long long v){
- update(i, j, v);
- update(k + 1, j, -v);
- update(k + 1, l + 1, v);
- update(i, l + 1, -v);
- }
- /// Query for sum of the sub-rectangle from upper-left [i,j] to lower-right [k,l]
- long long query(int i, int j, int k, int l){
- if (i > k || j > l) return 0;
- long long res = query(k, l) - query(i - 1, l) + query(i - 1, j - 1) - query(k, j - 1);
- return res;
- }
- };
- /// 2D Fenwick Tree with HashMap
- /// When N = 10^5, runs in 0.8 seconds in codeforces server for random cases
- /// When N = 2 * 10^5, runs in 2.00 seconds in codeforces server for random cases
- #define MAX 200010
- #define HMOD 16777215
- int n, m, tree[HMOD + 71235];
- long long hashmap[HMOD + 71235];
- inline void add(int i, int j, int v){
- long long h = (((long long)i * 1000003) + j) + 917921;
- int k = h & HMOD;
- while (hashmap[k] && hashmap[k] != h) k++;
- hashmap[k] = h, tree[k] += v;
- }
- inline int find(int i, int j){
- long long h = (((long long)i * 1000003) + j) + 917921;
- int k = h & HMOD;
- while (hashmap[k] && hashmap[k] != h) k++;
- return (hashmap[k] ? tree[k] : 0);
- }
- /// Add v to ar[i][j]
- inline void update(int i, int j, int v){
- while (i <= n){
- int k = j;
- while (k <= m){
- add(i, k, v);
- k += (k & (-k));
- }
- i += (i & (-i));
- }
- }
- /// Query for sum of the sub-rectangle from upper-left [i,j] to lower-right [n,n]
- inline int query(int i, int j){
- if ((i < 0) || (j < 0) || (i > n) || (j > m)) return 0;
- int res = 0;
- while (i){
- int k = j;
- while (k){
- res += find(i, k);
- k ^= (k & (-k));
- }
- i ^= (i & (-i));
- }
- return res;
- }
- /// Query for sum of the sub-rectangle from upper-left [i,j] to lower-right [k,l]
- inline int query(int i, int j, int k, int l){
- if (i > k || j > l) return 0;
- int res = query(k, l) - query(i - 1, l) + query(i - 1, j - 1) - query(k, j - 1);
- return res;
- }
- int main(){
- clock_t start = clock();
- int q, i, j, k, l, x, y, z;
- n = 200000;
- m = n, q = n;
- long long res = 0;
- while (q--){
- int flag = ran(0, 1);
- if (flag == 0){
- i = ran(1, n), k = ran(i, n);
- j = ran(1, m), l = ran(j, m);
- res += query(i, j, k, l);
- }
- if (flag == 1){
- i = ran(1, n), j = ran(1, m), x = ran(1, 100);
- update(i, j, x);
- }
- }
- printf("%0.5f\n", (clock() - start) / (1.0 * CLOCKS_PER_SEC));
- return 0;
- }
- /// DSU on subtree
- /// Codeforces 601D
- /// D[i] = number of distinct strings starting at vertex i and ending on some vertex down subtree i
- #define MAX 300010
- const long long HMOD[] = {2078526727, 2117566807};
- const long long BASE[] = {1572872831, 1971536491};
- char str[MAX];
- vector <int> adj[MAX];
- int n, C[MAX], D[MAX], T[MAX];
- set <long long> S[MAX];
- void dfs(int i, int p, long long h1, long long h2){ /// hash = 400687
- h1 = (h1 * BASE[0] + str[i - 1] + 10007) % HMOD[0];
- h2 = (h2 * BASE[1] + str[i - 1] + 10007) % HMOD[1];
- int j, k, x, idx = 0, res = 0, len = adj[i].size();
- for (j = 0; j < len; j++){
- x = adj[i][j];
- if (x != p){
- dfs(x, i, h1, h2);
- if (D[x] > res) res = D[x], idx = x; /// update
- }
- }
- if (idx) T[i] = T[idx]; /// If maximum subtree child found, set root to root of subtree
- for (j = 0; j < len; j++){
- x = adj[i][j];
- if (x != p && T[x] != T[i]){
- for (auto it: S[T[x]]) S[T[i]].insert(it); /// If not parent and not maximum subtree, insert
- S[T[x]].clear(); /// Finally clear the remaining items since not required anymore
- }
- }
- S[T[i]].insert((h1 << 31) ^ h2);
- D[i] = S[T[i]].size();
- }
- int main(){
- int i, j, k, l, a, b, c, x, res;
- scanf("%d", &n);
- for (i = 1; i <= n; i++) T[i] = i;
- for (i = 1; i <= n; i++) scanf("%d", &C[i]); /// Set parent[i] = i
- scanf("%s", str);
- for (i = 1; i < n; i++){
- scanf("%d %d", &a, &b);
- adj[a].push_back(b);
- adj[b].push_back(a);
- }
- dfs(1, 0, 0, 0);
- for (res = 0, c = 0, i = 1; i <= n; i++){
- x = C[i] + D[i];
- if (x > res) res = x, c = 1;
- else if (x == res) c++;
- }
- printf("%d\n%d\n", res, c);
- return 0;
- }
Add Comment
Please, Sign In to add comment