Cod sursa(job #1420219)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 17 aprilie 2015 22:44:35
Problema Potrivirea sirurilor Scor 40
Compilator cpp Status done
Runda Arhiva educationala Marime 4.27 kb
#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ULL;

const int Lmax = 100000;
const int INF = numeric_limits<int>::max() / 2;
const ULL BASE = 137;

ULL base[Lmax];

struct Node
{
    char key;
    int priority;
    int nr_nodes;

    Node *st, *dr;

    ULL codeHash;

    Node(char k, int p, int n, Node *l, Node *r) : key(k), priority(p), nr_nodes(n), st(l), dr(r), codeHash(k) {

        this->codeHash = static_cast<ULL>(this->key);
    }
};

Node *root, *NIL;

void initBaseVector()
{
    base[0] = 1;

    for (int i = 1; i < Lmax; ++i)
        base[i] = base[i - 1] * BASE;
}

void initTreap()
{
    srand(time(nullptr));
    NIL = new Node(0, 0, 0, nullptr, nullptr);
    root = NIL;
}

void update(Node *&T)
{
    T->nr_nodes = T->st->nr_nodes + T->dr->nr_nodes + 1;

    ULL code = T->st->codeHash;
    code = code * BASE + static_cast<ULL>(T->key);
    code = code * base[T->dr->nr_nodes] + T->dr->codeHash;
    T->codeHash = code;
}

void rotateRight(Node *&T)
{
    Node *aux = T->st;
    T->st = aux->dr;
    aux->dr = T;

    update(T);
    update(aux);

    T = aux;
}

void rotateLeft(Node *&T)
{
    Node *aux = T->dr;
    T->dr = aux->st;
    aux->st = T;

    update(T);
    update(aux);

    T = aux;
}

void balance(Node *&T)
{
    if (T->st->priority > T->priority)
        rotateRight(T);

    if (T->dr->priority > T->priority)
        rotateLeft(T);

    update(T);
}

void insert(Node *&T, int pos, char key, int priority = 1 + rand() % (INF - 2))
{
    if (T == NIL)
    {
        T = new Node(key, priority, 1, NIL, NIL);
    }
    else
    {
        if (pos <= T->st->nr_nodes + 1)
            insert(T->st, pos, key, priority);
        else
            insert(T->dr, pos - T->st->nr_nodes - 1, key, priority);

        balance(T);
    }
}

void erase(Node *&T, int pos)
{
    if (T == NIL) return;

    if (T->st->nr_nodes + 1 == pos)
    {
        if (T->st == NIL && T->dr == NIL)
        {
            delete T;
            T = NIL;
        }
        else
        {
            if (T->st->priority > T->dr->priority)
            {
                rotateRight(T);
                erase(T->dr, pos - T->st->nr_nodes - 1);
            }
            else
            {
                rotateLeft(T);
                erase(T->st, pos);
            }
        }
    }
    else
    {
        if (pos <= T->st->nr_nodes)
            erase(T->st, pos);
        else
            erase(T->dr, pos - T->st->nr_nodes - 1);
    }

    if (T != NIL)
        update(T);
}

char kth_element(Node *&T, int pos)
{
    if (T->st->nr_nodes + 1 == pos)
        return T->codeHash;

    if (pos <= T->st->nr_nodes)
        return kth_element(T->st, pos);
    else
        return kth_element(T->dr, pos - T->st->nr_nodes - 1);
}

void merge(Node *&root, Node *&L, Node *&R)
{
    root = new Node(0, INF, 1, L, R);
    update(root);

    erase(root, root->st->nr_nodes + 1);
}

/// [0...pos-1] U [pos...sizeTreap]
void split(Node *&root, Node *&L, Node *&R, int pos)
{
    insert(root, pos, 'a', INF);

    L = root->st;
    R = root->dr;

    delete root;
    root = NIL;
}

/// [x...y]
ULL getHash(int x, int y)
{
    ULL code = 0;
    Node *tmp, *T1, *T2, *T3;

    split(root, tmp, T3, y + 1);
    split(tmp, T1, T2, x);

    code = T2->codeHash;

    merge(tmp, T1, T2);
    merge(root, tmp, T3);

    return code;
}

void print(Node *&R = root)
{
    if (R == NIL) return;

    print(R->st);
    cout << R->key;
    print(R->dr);
}

void insert(int pos, char ch)
{
    insert(root, pos, ch);
}

void erase(int pos)
{
    erase(root, pos);
}

char kth_element(int pos)
{
    return kth_element(root, pos);
}

ULL genHash(const string str)
{
    ULL code = 0;

    for (char c: str)
        code = code * BASE + c;

    return code;
}

int main()
{
    ifstream in("strmatch.in");
    ofstream out("strmatch.out");

    initBaseVector();
    initTreap();

    string A, B;
    in >> A >> B;

    ULL codeHash = genHash(A);
    const int N = A.size();
    const int M = B.size();

    for (int i = 0; i < M; ++i)
        insert(i + 1, B[i]);

    vector<int> sol;

    for (int i = 1; i + N - 1 <= M; ++i)
    {
        if (getHash(i, i + N - 1) == codeHash)
            sol.push_back(i - 1);
    }

    out << sol.size() << "\n";

    for (int i = 0; i < min(1000, (int)sol.size()); ++i)
        out << sol[i] << " ";

    return 0;
}