HDU-4339 Query 线段树+多项式插值hash

这题主要是要将两个串的比较进行优化,不能够每次都从起始位置进行匹配。

这里用到了线段树进行优化,将每段区间的hash值进行更新和维护,通过找某一点的有连续段最长相同串即可。

代码如下:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MOD 100000003
#define T 29LL
using namespace std;
typedef unsigned int Int64;

// 这里建立棵线段树记录某一短区间的hash值 

char str[2][1000005];

Int64 _pow[1000005];

int ans;

struct Node
{
    int l, r;//, key1, key2;
    Int64 rkey1, rkey2;
}s[4000005];

void pre()
{
    _pow[0] = 1;
    for (int i = 1; i <= 1000000; ++i) {
        _pow[i] = _pow[i-1] * T;    
    }    
}
void push_up(int p)
{
    s[p].rkey1 = s[p<<1].rkey1 + s[p<<1|1].rkey1*_pow[s[p<<1].r-s[p<<1].l+1];
    s[p].rkey2 = s[p<<1].rkey2 + s[p<<1|1].rkey2*_pow[s[p<<1].r-s[p<<1].l+1];
}

void build(int p, int l, int r)
{
    s[p].l = l, s[p].r = r;
    if (l != r) {
        int mid = (l + r) >> 1;
        build(p<<1, l, mid);
        build(p<<1|1, mid+1, r);
        push_up(p);
    }
    else {
        s[p].rkey1 = str[0][r];
        s[p].rkey2 = str[1][r]; 
    }
}

void modify(int p, int kind, int pos, char val)
{
    if (s[p].l == s[p].r) {
        if (kind == 1) {
            s[p].rkey1 = val - 'a';    
        }    
        else {
            s[p].rkey2 = val - 'a';    
        }
    }
    else {
        int mid = (s[p].l + s[p].r) >> 1;
        if (pos <= mid) {
            modify(p<<1, kind, pos, val);    
        }    
        else {
            modify(p<<1|1, kind, pos, val);    
        }
        push_up(p);
    }
}

int find(int p)
{
    if (s[p].rkey1 == s[p].rkey2) {
        return s[p].r - s[p].l + 1;    
    }
    else if (s[p].l != s[p].r){
        int ret = find(p<<1);
        if (ret == s[p<<1].r - s[p<<1].l + 1) {
            ret += find(p<<1|1);
        }
        return ret;
    }
    else {
        return 0;
    }
}

int query(int p, int x)
{
    if (s[p].l == s[p].r) { 
        if (s[p].rkey1 == s[p].rkey2) {
            return 1;    
        }    
        else {
            return 0;
        }
    }
    else {
        int mid = (s[p].l + s[p].r) >> 1, ret = 0;
        if (x <= mid) {
            ret = query(p<<1, x);
            if (ret == s[p<<1].r-x+1) {  // 左边已经连续且饱满 
                ret += find(p<<1|1);
            }
        }    
        else {
            ret = query(p<<1|1, x);    
        }
        return ret;
    } 
}

int main()
{
    int M, Q, len1, len2, cnt, op, ca = 0, x, y;
    char t[5];
    pre();
    scanf("%d", &M);
    while (M--) {
        scanf("%s %s", str[0], str[1]);
        len1 = strlen(str[0]);
        len2 = strlen(str[1]);
        cnt = min(len1, len2);
        for (int i = 0; i < cnt; ++i) {
            str[0][i] -= 'a', str[1][i] -= 'a';
        } // 进行脱字母化,这样能够使T的取值变小 
        build(1, 0, cnt-1);
        scanf("%d", &Q);
        printf("Case %d:\n", ++ca);
        while (Q--) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d %d %s", &x, &y, t);
                if (y >= cnt) { continue; }
                modify(1, x, y, t[0]);
            }
            else {
                scanf("%d", &x);
                if (x >= cnt) {
                    puts("0");
                    continue;
                }
                printf("%d\n", query(1, x)); 
            }
        }
    }
    return 0;    
}
posted @ 2012-08-04 22:17  沐阳  阅读(366)  评论(0编辑  收藏  举报