UVA11402 - Ahoy, Pirates!(线段树)

题目链接

题目大意:给你n个01串,每个串拼接m次得到新串,最后在把这n个新串拼接起来得到最终的目标串。

然后给你四种操作:

F a b :把位置a到b都置为1;

E a b :把位置a到b都置为0;

I a b :把位置a到b上的数字翻转(0,1互换);

S a b :查询位置a到b有多少个1.

解题思路:线段树节点内部附加信息:setv:标记这个结点范围内有set值,并且需要传递到这个节点的孩子。resv:标记这个节点范围内有翻转,并且也需要传递到这个节点的孩子。注意:setv和resv标记的范围是节点u的孩子,并不包括本身,所以还需要根据父亲节点附加信息处理这个节点的值。还有这题的时间很紧,对于那些经常需要调用的函数加上inline可以加快速度。

代码:

#include <cstdio>
#include <cstring>

#define lson(x) (x<<1)
#define rson(x) ((x<<1) + 1)

const int maxn = 1100000;
int v[maxn];

struct Node {

    int l, r, v;
    int setv, resv;
    void set (int l, int r, int v, int setv, int resv) {

        this->l = l;
        this->r = r;
        this->v = v;
        this->setv = setv;
        this->resv = resv;
    }
}node[4 * maxn];

inline void pushup (int u) {

    node[u].set(node[lson(u)].l, node[rson(u)].r, node[lson(u)].v + node[rson(u)].v, -1, 0);
}

inline void set_node(int u, int v) {

    node[u].setv = v;
    node[u].resv = 0;
    node[u].v = v * (node[u].r - node[u].l + 1);
}

inline void res_node(int u) {

    node[u].resv ^= 1;
    node[u].v = node[u].r - node[u].l + 1 - node[u].v;
}

inline void pushdown (int u) {

    if (node[u].setv >= 0) {

        set_node(lson(u), node[u].setv);
        set_node(rson(u), node[u].setv);
        node[u].setv = -1;
    }

    if (node[u].resv) {

        res_node(lson(u));
        res_node(rson(u));
        node[u].resv = 0;
    }
}

void build (int u, int l, int r) {

    if (l == r)
        node[u].set(l, r, v[l - 1], -1, 0);
    else {

        int m = (l + r) / 2;
        build (lson(u), l, m);
        build (rson(u), m + 1, r);
        pushup(u);
    }
}

void update (int u, int l, int r, int v) {

    if (node[u].l >= l && node[u].r <= r) {
        set_node(u, v);
        return;
    }
    int m = (node[u].l + node[u].r) / 2;

    pushdown(u);
    if (l <= m)
        update (lson(u), l, r, v);
    if (r > m)
        update (rson(u), l, r, v);
    pushup(u);
}

void reserve (int u, int l, int r) {

    if (node[u].l >= l && node[u].r <= r) {
        res_node(u);
        return;
    }

    int m = (node[u].l + node[u].r) / 2;

    pushdown(u);
    if (l <= m)
        reserve(lson(u), l, r);
    if (r > m)
        reserve(rson(u), l, r);
    pushup(u);
}

int query (int u, int l, int r) {

    if (node[u].l >= l && node[u].r <= r)
        return node[u].v;

    int m = (node[u].l + node[u].r) / 2;

    int ret = 0;
    pushdown(u);
    if (l <= m)
        ret += query (lson(u), l, r);
    if (r > m)
        ret += query (rson(u), l, r);
    pushup(u);

    return ret;
}

int main () {

    int T, n, t, q;
    int x, y;
    int N, len;
    char s[100];

    scanf ("%d", &T);

    for (int i = 1; i <= T; i++) {

        printf ("Case %d:\n", i);
        memset (v, 0, sizeof (v));
        len = 0;

        scanf ("%d", &n);
        while (n--) {

            scanf ("%d%s", &t, s);
            N = strlen (s);
            for (int j = 0; j < t; j++)
                for (int k = 0; k < N; k++) {
                    if (s[k] == ‘1‘)
                        v[len] = 1;
                    len++;
                }
        }

        build(1, 1, len);

        scanf ("%d", &q);
        int cas = 0;
        while (q--) {
            scanf ("%s%d%d", s, &x, &y);
            if (s[0] == ‘F‘)
                update(1, x + 1, y + 1, 1);
            else if (s[0] == ‘E‘)
                update (1, x + 1, y + 1, 0);
            else if (s[0] == ‘I‘)
                reserve(1, x + 1, y + 1);
            else
                printf ("Q%d: %d\n", ++cas, query(1, x + 1, y + 1));
        }
    }
    return 0;
}
时间: 2024-08-21 14:40:45

UVA11402 - Ahoy, Pirates!(线段树)的相关文章

UVA - 11402 Ahoy, Pirates! (线段树)

In the ancient pirate ages, the Pirate Land was divided into two teams ofpirates, namely, the Buccaneer and the Barbary pirates.Each pirate's team was not fixed, sometimes the opponent pirates attacked andhe was taken away to the other pirate team. A

线段树(I tree)

Codeforces Round #254 (Div. 2)E题这题说的是给了一个一段连续的区间每个区间有一种颜色然后一个彩笔从L画到R每个区间的颜色都发生了 改变然后 在L和R这部分区间里所用的颜色变成了x 然后每个区间的 色度加上abs(x-Yi) Yi 为原位置的颜色,还有一个操作就是求 L 到 R 的距离之内的所有的点和,数据 有 n<=100000 m<100000 次操作 对于每次第二种操作输出, 自然我们将一个区间的颜色如果相同自然将他们 用延迟标记 但是 会有一个问题就是在一个

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列