Cod sursă (job #143316)

Utilizator avatar spatarel Spatarel Dan-Constantin spatarel IP ascuns
Problemă Sir3 (lot liceu) Compilator cpp | 8,14 kb
Rundă Status evaluat
Dată 17 apr. 2015 20:33:10 Scor ascuns
/*
 * Olimpiada Națională de Informatică, Pitești 2014
 *
 * © 2014 Bogdan Cristian Tătăroiu
 */

#include <cstdio>
#include <cassert>
#include <list>
#include <string>
#include <vector>
#include <cstring>

const int MAXL = 70000;
const int MAXQ = 100000;
const int MAXC = 500000;
const int REPTR = 1000;

using namespace std;

int L, C, Q, Lptr;

char initStr[MAXL + 1];
vector<int> lens;
vector<string> words;
int aib[MAXL + 3];

list<char> str;
vector<list<char> :: iterator> ptrs;

/*
int trieLeft[MAXC][26], tLeftCnt = 0;
int trieRight[MAXC][26], tRightCnt = 0;
*/

inline void add(int poz, int val) {
    for (poz += 2; poz < MAXL + 3; poz += (poz ^ (poz - 1)) & poz) {
        aib[poz] += val;
    }
}

inline int query(int poz) {
    int val = 0;
    for (poz += 2; poz; poz &= (poz - 1)) {
        val += aib[poz];
    }
    return val;
}

/*
inline int add_word(char word[]) {
    int node = 0, len = 0;
    char *p;
    for (p = word; *p; p++, len++) {
        if (trieLeft[node][*p - 'a'] == -1) {
            tLeftCnt += 1;
            trieLeft[node][*p - 'a'] = tLeftCnt;
        }
        node = trieLeft[node][*p - 'a'];
    }
    node = 0;
    for (p--; p != word; p--) {
        if (trieRight[node][*p - 'a'] == -1) {
            tRightCnt += 1;
            trieRight[node][*p - 'a'] = tRightCnt;
        }
        node = trieRight[node][*p - 'a'];
    }
    return len;
}
*/

inline pair<int, int> findPtrPoz(int poz) {
    // argmax_{ptrPoz} (ptrPoz + sum_0^{ptrPoz - 1} cnt[i] <= poz)
    // argmax_{ptrPoz} (ptrPoz + aib(ptrPoz - 1) <= poz)
    int ptrPoz = 0, step = 1 << 16;
    int curSum = 0;
    for (; step; step >>= 1) {
        if (ptrPoz + step - 1 < Lptr &&
            (ptrPoz + step - 1) + (curSum + aib[ptrPoz + step]) <= poz) {
            ptrPoz += step;
            curSum += aib[ptrPoz];
        }
    }

    /*
    for (; step; step >>= 1) {
        if (ptrPoz + step - 1 < Lptr &&
            ptrPoz + step - 1 + query(ptrPoz + step - 2) <= poz) {
            ptrPoz += step;
        }
    }
    int curSum = query(ptrPoz - 2);
    */
    return make_pair(ptrPoz - 1, curSum);
}

list<char> :: iterator walk(int ptr_poz, int between, int in_chain) {
    list<char> :: iterator it;
    if (in_chain <= between - in_chain + 1 || ptr_poz + 1 == Lptr) {
        it = ptrs[ptr_poz];
        for (int i = 0; i < in_chain; i++) {
            it++;
        }
    } else {
        it = ptrs[ptr_poz + 1];
        for (int i = 0; i < between - in_chain + 1; i++) {
            it--;
        }
    }
    return it;
}

int main() {
    assert(freopen("sir3.in", "rt", stdin));
    //assert(freopen("in", "rt", stdin));
#ifndef DEBUG
    assert(freopen("sir3.out", "wt", stdout));
#endif

    assert(scanf(" %s", initStr) == 1);
    for (L = 0; initStr[L]; L++) {
        str.push_back(initStr[L]);
        ptrs.push_back(str.end());
        ptrs.back()--;
    }
    Lptr = L;

    /*
    memset(trieLeft, -1, sizeof(trieLeft));
    memset(trieRight, -1, sizeof(trieRight));
    */

    assert(scanf("%d", &C) == 1);
    assert(1 <= C && C <= MAXC);
    lens.reserve(C);
    words.reserve(C);
    for (int i = 0; i < C; i++) {
        assert(scanf(" %s", initStr) == 1);
        words.push_back(initStr);
        lens.push_back(words.back().size());
    }

    assert(scanf("%d", &Q) == 1);
    assert(1 <= Q && Q <= MAXQ);
    int last_ans = 0;
    int rePtr = REPTR;
    int aa, bb;
    // Q = 430;
    for (int i = 0; i < Q; i++) {
        rePtr -= 1;
        if (rePtr == 0) {
            rePtr = REPTR;
            ptrs.clear();
            for (list<char> :: iterator it = str.begin();
                 it != str.end(); it++) {
                ptrs.push_back(it);
            }
            Lptr = L;
            memset(aib, 0, sizeof(aib));
        }

        int type, poz;
        assert(scanf("%d %d", &type, &poz) == 2);
        assert(type == 0 || type == 1);
        if (type == 0) {
            char c;
            assert(scanf(" %c", &c) == 1);
            assert(scanf("%d %d", &aa, &bb) == 2);
            if(last_ans == 0) poz ^= aa;
            else poz ^= bb;
            
            assert(1 <= poz && poz <= L + 1);
            poz -= 1;
            // assert('a' <= c && c <= 'z');

            pair<int, int> pp = findPtrPoz(poz);
            int ptr_poz = pp.first;
            int cur_sum = pp.second;
            /*
            assert(ptr_poz + query(ptr_poz - 1) <= poz);
            assert(ptr_poz + 1 >= Lptr ||
                   ptr_poz + 1 + query(ptr_poz) > poz);
            assert(cur_sum == query(ptr_poz - 1));
            */
            int between = query(ptr_poz) - cur_sum;
            int in_chain = poz - (ptr_poz + cur_sum);

            // printf("\tadd %d %c\n", poz, c);
            list<char> :: iterator it = walk(ptr_poz, between, in_chain);
            str.insert(it, c);
            if (in_chain == 0) {
                it--;
                ptrs[ptr_poz] = it;
            }
            add(ptr_poz, 1);
            L += 1;
        } else {
            int word;
            assert(scanf("%d", &word) == 1);
            assert(1 <= word && word <= C);  
            assert(scanf("%d %d", &aa, &bb) == 2);
            
            if(last_ans == 0) poz ^= aa;
            else poz ^= bb; 

            assert(1 <= poz && poz <= L);
            poz -= 1;
           
            word -= 1;

            // printf("\tquery %d %d\n", poz, word);
            if (poz + 1 < lens[word]) {
                printf("0\n");
                continue;
            }

            pair<int, int> pp[2] = {findPtrPoz(poz),
                                    findPtrPoz(poz - lens[word] + 1)};
            int ptr_poz[2] = {pp[0].first, pp[1].first};
            int cur_sum[2] = {pp[0].second, pp[1].second};
            /*
            assert(cur_sum[0] == query(ptr_poz[0] - 1));
            assert(cur_sum[1] == query(ptr_poz[1] - 1));
            assert(ptr_poz[0] + query(ptr_poz[0] - 1) <= poz);
            assert(ptr_poz[0] + 1 + query(ptr_poz[0]) > poz);
            assert(cur_sum[0] == query(ptr_poz[0] - 1));
            assert(ptr_poz[1] + query(ptr_poz[1] - 1) <= poz - lens[word] + 1);
            assert(ptr_poz[1] + 1 + query(ptr_poz[1]) > poz - lens[word] + 1);
            assert(cur_sum[1] == query(ptr_poz[1] - 1));
            */
            int between[2] = {query(ptr_poz[0]) - cur_sum[0],
                              query(ptr_poz[1]) - cur_sum[1]};
            int in_chain[2] = {poz - (ptr_poz[0] + cur_sum[0]),
                               poz - lens[word] + 1 - (ptr_poz[1] + cur_sum[1])};
            int cst[2] = {min(in_chain[0], between[0] - in_chain[0] + 1),
                          min(in_chain[1], between[1] - in_chain[1] + 1)};

            /*
            printf("\tptr_poz %d %d\n\tcur_sum %d %d\n",
                   ptr_poz[0], ptr_poz[1], cur_sum[0], cur_sum[1]);
            printf("\tbetween %d %d\n\tin_chain %d %d\n",
                   between[0], between[1], in_chain[0], in_chain[1]);
            printf("\tcst[0] = %d cst[1] = %d\n", cst[0], cst[1]);
            */

            bool match;
            if (cst[0] < cst[1]) {
                match = 1;
                list<char> :: iterator it = \
                    walk(ptr_poz[0], between[0], in_chain[0]);

                string :: reverse_iterator sit;
                for (sit = words[word].rbegin();
                     sit != words[word].rend() && match; sit++) {
                    // printf("\t\t%c %c\n", *it, *sit);
                    match = *it == *sit;
                    it--;
                }
            } else {
                match = 1;
                list<char> :: iterator it = \
                    walk(ptr_poz[1], between[1], in_chain[1]);

                string :: iterator sit;
                for (sit = words[word].begin();
                     sit != words[word].end() && match; sit++) {
                    // printf("\t\t%c %c\n", *it, *sit);
                    match = *it == *sit;
                    it++;
                }
            }
            last_ans = match ? 1 : 0;
            printf("%d\n", last_ans);
        }

        /*
        for (list<char> :: iterator it = str.begin(); it != str.end(); it++) {
            printf("%c", *it);
        }
        printf("\n");
        */
    }
    return 0;
}