Submission #570414

#TimeUsernameProblemLanguageResultExecution timeMemory
570414cjoaSelling RNA Strands (JOI16_selling_rna)C++17
100 / 100
177 ms66316 KiB
#include <iostream>

#include <string>
#include <vector>
#include <algorithm>
#include <bitset>
#include <cstring>
#include <cassert>

using namespace std;

#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(...) DBG2::cprint(#__VA_ARGS__, __LINE__, __VA_ARGS__)
#else
#define DEBUG(...)
#endif


using VI = vector<int>;
using II = pair<int,int>;


class BinaryIndexedTree {
   int N;
   vector<int> tree;
public:
   BinaryIndexedTree(int _N) : N(_N), tree(_N+1) {}

   int query(int idx) const {
      assert(idx <= N);
      int res = 0;
      for (int i = idx; i > 0; i -= (i & -i))
         res += tree[i];
      return res;
   }

   int query(int L, int R) const {
      R = min(R, N);
      L = max(L, 1);
      return L <= R ? query(R) - query(L-1) : 0;
   }

   void update(int idx, int val = 1) {
      for (int i = idx; i <= N; i += (i & -i))
         tree[i] += val;
   }
};

struct Trie {
   struct TrieNode {
      int child[4];
      TrieNode() {
         memset(child, -1, sizeof(child));
      }
   };

   vector<TrieNode> nodes;

   static const int root = 0;   // root is at index 0

   Trie() {
   // nodes.reserve(8000000);
      nodes.push_back(TrieNode());  // 1st node is root
   }

   int insert(const string& S) {
      int cur = root;
      for (char c : S) {
         int k = c - '0';
         int nxt = nodes[cur].child[k];
         if (nxt < 0) {
            nxt = nodes.size();
            nodes.push_back(TrieNode());
            nodes[cur].child[k] = nxt;
         }
         cur = nxt;
      }
      return cur;
   }

   int dfs_time;
   VI dfs_start, dfs_end;
   void dfs(int cur) {
      dfs_start[cur] = ++dfs_time;
      for (int k = 0; k < 4; ++k) {
         int nxt = nodes[cur].child[k];
         if (nxt < 0) continue;
         dfs(nxt);
      }
      dfs_end[cur] = dfs_time;
   }
   
   void explore() {
      dfs_time  = 0;
      dfs_start = VI(nodes.size());
      dfs_end   = VI(nodes.size());
      dfs(root);
   }

   int find(const string& S) {
      int cur = root;
      for (char c : S) {
         int k = c - '0';
         int nxt = nodes[cur].child[k];
         if (nxt < 0) return -1;
         cur = nxt;
      }
      return cur;
   }
};

const string valid_chars = "ACGU";
void transform(string& S) {
   for (int i = 0; i < (int) S.size(); ++i)
      S[i] = '0' + valid_chars.find( S[i] );
}

struct Rect {
   II tl, br;
};

struct Event {
   int id, x;
   char type;
};

int main(int argc, char* argv[]) {
   ios_base::sync_with_stdio(false); 
   cin.tie(NULL);

   Trie trie_fwd, trie_rev;

   int N, M;
   cin >> N >> M;

   vector<II> IDs;

   for (int i = 0; i < N; ++i) {
      string chain;
      cin >> chain;
      transform(chain);
      int idx = trie_fwd.insert(chain);
      reverse(chain.begin(), chain.end());
      int idy = trie_rev.insert(chain);
      IDs.emplace_back(idx, idy);
   }
   DEBUG(IDs);

   trie_fwd.explore();
   trie_rev.explore();

   vector<II> points;
   for (II id : IDs) {
      points.emplace_back(
         trie_fwd.dfs_start[id.first],
         trie_rev.dfs_start[id.second]
      );
   }
   for (int i = 0; i < N; ++i)
      DEBUG(i, points[i]);

   vector<Rect> rects;
   for (int j = 0; j < M; ++j) {
      string prefix, suffix;
      cin >> prefix >> suffix;
      transform(prefix);
      transform(suffix);
      reverse(suffix.begin(), suffix.end());

      int idx = trie_fwd.find(prefix);
      int idy = trie_rev.find(suffix);
      if (idx < 0 or idy < 0) {
         rects.push_back({
            II(-1, -1), II(-1, -1)
         });
      }
      else {
         rects.push_back({
            II(trie_fwd.dfs_start[idx], trie_rev.dfs_start[idy]),
            II(trie_fwd.dfs_end[idx], trie_rev.dfs_end[idy])
         });
      }
   }

   for (int j = 0; j < M; ++j)
      DEBUG(j, rects[j].tl, rects[j].br);

   vector<Event> events;
   for (int i = 0; i < N; ++i)
      events.push_back({ i, points[i].first, 'P' });

   for (int j = 0; j < M; ++j) {
      if (rects[j].tl.first < 0) continue;

      events.push_back({ j, rects[j].tl.first, 'L'});
      events.push_back({ j, rects[j].br.first, 'R'});
   }

   sort(events.begin(), events.end(),
      [&] (Event a, Event b) -> bool {
         if (a.x != b.x)
            return a.x < b.x;
         if (a.type != b.type)
            return a.type < b.type;
         return a.id < b.id;
      }
   );

   vector<int> ans(M);
   BinaryIndexedTree bit(trie_rev.dfs_time+1);

   for (Event e : events) {
      DEBUG(e.id, e.type, e.x);
      if (e.type == 'P') {
         int y = points[e.id].second;
         bit.update(y);
      }
      else if (e.type == 'L') {
         int ty = rects[e.id].tl.second;
         int by = rects[e.id].br.second;
         ans[e.id] += -bit.query(ty, by);
      }
      else {
         int ty = rects[e.id].tl.second;
         int by = rects[e.id].br.second;
         ans[e.id] += bit.query(ty, by);
      }
   }

   for (int j = 0; j < M; ++j)
      cout << ans[j] << '\n';

   return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...