Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.*;
- import java.util.*;
- class Main {
- public static void main(String[] args) throws Exception {
- BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
- PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out), false);
- new Main(in, out);
- out.close();
- }
- BIT[] sz;
- BIT[][] cnt;
- Trie[] trie;
- Main(BufferedReader in, PrintWriter out) throws Exception {
- String[] vals = in.readLine().split(" ");
- int n = Integer.parseInt(vals[0]);
- int q = Integer.parseInt(vals[1]);
- String[] words = new String[n+1];
- init(n);
- for (int i = 1; i <= n; ++i) {
- words[i] = in.readLine();
- }
- Query[] queries = new Query[q];
- for (int i = 0; i < q; ++i) {
- vals = in.readLine().split(" ");
- queries[i] = new Query();
- queries[i].i = i;
- queries[i].l = Integer.parseInt(vals[0]);
- queries[i].r = Integer.parseInt(vals[1]);
- }
- Arrays.sort(queries, new Comparator<Query>() {
- @Override
- public int compare(Query q1, Query q2) {
- return Integer.compare(q1.r, q2.r);
- }
- });
- for (int i = 0, r = 0; i < q; ++i) {
- while (r < queries[i].r) {
- ++r;
- add(r, words[r]);
- }
- queries[i].v = solve(queries[i].l, queries[i].r);
- }
- Arrays.sort(queries, new Comparator<Query>() {
- @Override
- public int compare(Query q1, Query q2) {
- return Integer.compare(q1.i, q2.i);
- }
- });
- for (int i = 0; i < q; ++i) {
- out.println(queries[i].v);
- }
- }
- void init(int n) {
- sz = new BIT[2];
- trie = new Trie[2];
- cnt = new BIT[2][26];
- for (int i = 0; i < 2; ++i) {
- sz[i] = new BIT(n);
- trie[i] = new Trie();
- for (int j = 0; j < cnt[i].length; ++j) {
- cnt[i][j] = new BIT(n);
- }
- }
- }
- String reverse(String word) {
- StringBuilder sb = new StringBuilder(word);
- return sb.reverse().toString();
- }
- void add(int i, String word) {
- trie[0].add(i, word, sz[0], cnt[0]);
- trie[1].add(i, reverse(word), sz[1], cnt[1]);
- }
- long solve(int l, int r) {
- long ans = sz[0].query(l, r) * sz[1].query(l, r);
- for (int i = 0; i < 26; ++i) {
- ans -= cnt[0][i].query(l, r) * cnt[1][i].query(l, r);
- }
- return ans;
- }
- class Query {
- int i, l, r;
- long v;
- }
- class Trie {
- Trie[] edges;
- int lastIndex;
- Trie() {
- edges = new Trie[26];
- lastIndex = -1;
- }
- void add(int k, String word, BIT sz, BIT[] cnt) {
- Trie curr = this;
- for (int i = 0; i < word.length(); ++i) {
- int c = word.charAt(i) - 'a';
- if (curr.edges[c] == null) {
- curr.edges[c] = new Trie();
- } else {
- int j = curr.edges[c].lastIndex;
- sz.update(j, -1);
- if (i > 0) cnt[c].update(j, -1);
- }
- sz.update(k, 1);
- if (i > 0) cnt[c].update(k, 1);
- curr = curr.edges[c];
- curr.lastIndex = k;
- }
- }
- }
- class BIT {
- int[] arr;
- BIT(int size) {
- arr = new int[size+1];
- }
- void update(int p, int v) {
- while (p < arr.length) {
- arr[p] += v;
- p += (p & -p);
- }
- }
- long query(int p) {
- long ans = 0;
- while (p > 0) {
- ans += arr[p];
- p -= (p & -p);
- }
- return ans;
- }
- long query(int l, int r) {
- return query(r) - query(l-1);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement