二分+树状数组/线段树(区间更新) HDOJ 4339 Query

题目传送门

题意:给两串字符串,操作1:替换其中一个字符串的某个位置的字符 操作2:查询从p开始相等的最长连续长度

分析:树状数组可以维护一个区间内公共长度(连续)的情况,查询时用二分查找最远的端点即可。还可以用线段树去做,线段树能处理的问题很多,这题只要往右区间合并就行了。

收获:1.线段树的区间合并又做一题(虽然我写的还没AC) 2. 树状数组写起来方便又奇效!

代码1(树状数组):

/************************************************
* Author        :Running_Time
* Created Time  :2015-8-26 9:46:09
* File Name     :I.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e6 + 10;
const int Q = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
char s1[N], s2[N];
int L;
struct BIT   {
    int c[N];
    void init(void) {
        memset (c, 0, sizeof (c));
    }
    void updata(int i, int x)   {
        while (i <= L)   {
            c[i] += x;  i += (i & (-i));
        }
    }
    int query(int i)    {
        int ret = 0;
        while (i)   {
            ret += c[i];    i -= (i & (-i));
        }
        return ret;
    }
    int bsearch(int p, int l, int r)    {
        while (l <= r)  {
            int mid = (l + r) >> 1;
            if (query (mid) - query (p-1) == mid - p + 1)   l = mid + 1;
            else    r = mid - 1;
        }
        return l - p;
    }
}bit;

int main(void)    {
    int T, cas = 0; scanf ("%d", &T);
    while (T--) {
        scanf ("%s%s", s1 + 1, s2 + 1);
        int q;  scanf ("%d", &q);
        int len1 = strlen (s1 + 1), len2 = strlen (s2 + 1);
        L = min (len1, len2);

        bit.init ();
        for (int i=1; i<=L; ++i)    {
            if (s1[i] == s2[i]) bit.updata (i, 1);
        }
        printf ("Case %d:\n", ++cas);
        while (q--) {
            int op; scanf ("%d", &op);
            if (op == 1)    {
                int x, p;   char c; scanf ("%d%d %c", &x, &p, &c);
                ++p;
                if (p > L) continue;
                bool same = (s1[p] == s2[p]);
                if (x == 1) {
                    s1[p] = c;
                    if (same && s1[p] != s2[p])   bit.updata (p, -1);
                    else if (!same && s1[p] == s2[p])   bit.updata (p, 1);
                }
                else    {
                    s2[p] = c;
                    if (same && s1[p] != s2[p])   bit.updata (p, -1);
                    else if (!same && s1[p] == s2[p])   bit.updata (p, 1);
                }
            }
            else    {
                int p;  scanf ("%d", &p);
                ++p;
                if (p > L) {
                    puts ("0"); continue;
                }
                printf ("%d\n", bit.bsearch (p, p, L));
            }
        }
    }

    return 0;
}

代码2(线段树):

/************************************************
* Author        :Running_Time
* Created Time  :2015-8-26 9:46:09
* File Name     :I.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e6 + 10;
const int Q = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
char s1[N], s2[N];
struct ST   {
    int sum[N<<2];
    void push_up(int rt, int len)    {      //sum[rt<<1]表示从左子树线段左端点开始最长连续的公共的长度,如果全是公共的,
        if (sum[rt<<1] == len - (len >> 1)) sum[rt] = sum[rt<<1] + sum[rt<<1|1];        //合并右子树的线段长度
        else    sum[rt] = sum[rt<<1];
    }
    void build(int l, int r, int rt)    {
        if (l == r) {
            sum[rt] = s1[l] == s2[r] ? 1 : 0;
            return ;
        }
        int mid = (l + r) >> 1;
        build (lson);   build (rson);
        push_up (rt, r - l + 1);
    }
    void updata(int p, int c, int l, int r, int rt)    {
        if (l == r) {
            sum[rt] = c;  return ;
        }
        int mid = (l + r) >> 1;
        if (p <= mid)   updata (p, c, lson);
        else    updata (p, c, rson);
        push_up (rt, r - l + 1);
    }
    int query(int p, int l, int r, int rt)  {
        if (l == r) return sum[rt];
        int mid = (l + r) >> 1;
        if (p <= mid)   {
            int ret = query (p, lson);
            if (p + ret - 1 == mid) return ret + sum[rt<<1|1];
            else    return ret;
        }
        else    return query (p, rson);
    }
}st;

int main(void)    {
    int T, cas = 0; scanf ("%d", &T);
    while (T--) {
        scanf ("%s%s", s1 + 1, s2 + 1);
        int q;  scanf ("%d", &q);
        int len1 = strlen (s1 + 1), len2 = strlen (s2 + 1);
        int mn = min (len1, len2);
        st.build (1, mn, 1);

        printf ("Case %d:\n", ++cas);
        while (q--) {
            int op; scanf ("%d", &op);
            if (op == 1)    {
                int x, p;   char c; scanf ("%d%d %c", &x, &p, &c);
                ++p;
                if (p > mn) continue;                       //特殊情况特判
                if (x == 1) {
                    s1[p] = c;
                }
                else    {
                    s2[p] = c;
                }
                st.updata (p, (s1[p] == s2[p]), 1, mn, 1);
            }
            else    {
                int p;  scanf ("%d", &p);
                ++p;
                if (p > mn) {                               //特殊情况特判
                    puts ("0"); continue;
                }
                printf ("%d\n", st.query (p, 1, mn, 1));
            }
        }
    }

    return 0;
}

代码3(unAC):

/************************************************
* Author        :Running_Time
* Created Time  :2015-8-26 9:46:09
* File Name     :I.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e6 + 10;
const int Q = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
char s1[N], s2[N];
struct ST   {
    int sum[N<<2], lsum[N<<2], rsum[N<<2];
    void push_up(int rt, int len)    {
        lsum[rt] = lsum[rt<<1];
        rsum[rt] = rsum[rt<<1|1];
        sum[rt] = max (sum[rt<<1], sum[rt<<1|1]);
        if (lsum[rt] == len - (len >> 1))   lsum[rt] += lsum[rt<<1|1];
        if (rsum[rt] == len >> 1)   rsum[rt] += rsum[rt<<1];
        sum[rt] = max (rsum[rt<<1] + lsum[rt<<1|1], max (sum[rt<<1], sum[rt<<1|1]));
    }
    void build(int l, int r, int rt)    {
        if (l == r) {
            sum[rt] = lsum[rt] = rsum[rt] = s1[l] == s2[r] ? 1 : 0;
            return ;
        }
        int mid = (l + r) >> 1;
        build (lson);   build (rson);
        push_up (rt, r - l + 1);
    }
    void updata(int p, int c, int l, int r, int rt)    {
        if (l == r) {
            sum[rt] = lsum[rt] = rsum[rt] = c;  return ;
        }
        int mid = (l + r) >> 1;
        if (p <= mid)   updata (p, c, lson);
        else    updata (p, c, rson);
        push_up (rt, r - l + 1);
    }
    int query(int p, int l, int r, int rt)  {
        if (l == r) return sum[rt];
        int mid = (l + r) >> 1;
        if (p <= mid)   {
            if (p + rsum[rt<<1] - 1 >= mid)    return mid - p + 1 + query (p, rson);
            else    return query (p, lson);
        }
        else    return query (p, lson);
    }
}st;

int main(void)    {
    int T, cas = 0; scanf ("%d", &T);
    while (T--) {
        scanf ("%s%s", s1 + 1, s2 + 1);
        int q;  scanf ("%d", &q);
        int len1 = strlen (s1 + 1), len2 = strlen (s2 + 1);
        int mn = min (len1, len2);
        st.build (1, mn, 1);

        printf ("Case %d:\n", ++cas);
        while (q--) {
            int op; scanf ("%d", &op);
            if (op == 1)    {
                int x, p;   char c; scanf ("%d%d %c", &x, &p, &c);
                if (p + 1 > mn) continue;
                if (x == 1) {
                    s1[p+1] = c;
                }
                else    {
                    s2[p+1] = c;
                }
                st.updata (p+1, (s1[p+1] == s2[p+1]), 1, mn, 1);
            }
            else    {
                int p;  scanf ("%d", &p);
                if (p + 1 > mn) {
                    puts ("0"); continue;
                }
                printf ("%d\n", st.query (p + 1, 1, mn, 1));
            }
        }
    }

    return 0;
}

  

时间: 2024-10-06 09:29:08

二分+树状数组/线段树(区间更新) HDOJ 4339 Query的相关文章

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

[洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度.(L>=0) 2. 插入操作. 语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾. 限制:n是整数(可能为负数)并且在长整

hdu 1166 敌兵布阵——(区间和)树状数组/线段树

here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地.接下来有N个正整数,第i个正整数ai代表第i个工兵营地里開始时有ai个人(1<=ai<=50). 接下来每行有一条命令.命令有4种形式: (1) Add i j,i和j为正整数,表示第i个营地添加j个人(j不超过30) (2)Sub i j ,i和j为正整数,表示第i

HDU1556 Color the ball【树状数组】【区间更新】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1556 题目大意: N个气球排成一排,从左到右编号为1~N,给N组数据,每次给2两个整数s,e,表示从s到e将 气球涂色.当涂到N次以后已经忘记了第i个气球被涂过几次颜色了.现在来计算出每个气球被 涂了几次颜色,并输出出来. 思路: 典型的更新区间,单点求值问题.直接模拟会超时,考虑用树状数组来做.单点更新中,树状 数组表示区间的和.在区间更新中,树状数组表示单个元素的变化. 这道题中,区间(s,e

POJ 2155 Matrix【二维树状数组+YY(区间更新,单点查询)】

题目链接:http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 32950   Accepted: 11943 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th col

优先队列 + 并查集 + 字典树 + 树状数组 + 线段树 + 线段树点更新 + KMP +AC自动机 + 扫描线

这里给出基本思想和实现代码 . 优先队列 : 曾经做过的一道例题       坦克大战 1 struct node 2 { 3 int x,y,step; 4 friend bool operator <(node s1,node s2) // 定义结构体 的时候 这个 就是 用于 优先队列的 基准排序 5 { 6 return s1.step>s2.step; // 步数小的 在上 为小顶堆 7 } 8 }; 9 priority_queue<node>Q; // 优先队列的结构