LightOJ 1135 - Count the Multiples of 3 线段树

http://www.lightoj.com/volume_showproblem.php?problem=1135

题意:给定两个操作,一个对区间所有元素加1,一个询问区间能被3整除的数有多少个。

思路:要求被3整除,我们可以记录3个状态,当前区间模3余1的 余2的 余0的,那么对一个数增加的时候,直接交换不同余数下的个数就可以了。

/** @Date    : 2016-12-06-20.00
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version :
  */

#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

struct yuu
{
    int l, r;
    int add;
    int m0, m1, m2;
}tt[N << 2];

void pushup(int p)
{
    tt[p].m0 = tt[p << 1].m0 + tt[p << 1 | 1].m0;
    tt[p].m1 = tt[p << 1].m1 + tt[p << 1 | 1].m1;
    tt[p].m2 = tt[p << 1].m2 + tt[p << 1 | 1].m2;
}

void pushdown(int p)
{
    if(tt[p].add != 0)
    {
        tt[p].add %= 3;
        ///
        tt[p << 1].add += tt[p].add;
        if(tt[p].add == 2)
        {
            swap(tt[p << 1].m0 , tt[p << 1].m1);
            swap(tt[p << 1].m0 , tt[p << 1].m2);
        }
        else if(tt[p].add == 1)
        {
            swap(tt[p << 1].m0 , tt[p << 1].m2);
            swap(tt[p << 1].m1 , tt[p << 1].m0);
        }
        ///
        tt[p << 1 | 1].add += tt[p].add;
        if(tt[p].add == 2)
        {
            swap(tt[p << 1 | 1].m0 , tt[p << 1 | 1].m1);
            swap(tt[p << 1 | 1].m0 , tt[p << 1 | 1].m2);
        }
        else if(tt[p].add == 1)
        {
            swap(tt[p << 1 | 1].m0 , tt[p << 1 | 1].m2);
            swap(tt[p << 1 | 1].m1 , tt[p << 1 | 1].m0);
        }
        tt[p].add = 0;
    }
}

void build(int l, int r, int p)
{
    tt[p].l = l;
    tt[p].r = r;
    tt[p].add = tt[p].m0 = tt[p].m2 = tt[p].m1 = 0;
    if(l == r)
    {
        tt[p].m0 = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(l , mid, p << 1);
    build(mid + 1, r, p << 1 | 1);
    pushup(p);
}

void updata(int l, int r, int v, int p)
{
    if(l <= tt[p].l && r >= tt[p].r)
    {
        tt[p].add += v;
        swap(tt[p].m0 , tt[p].m2);
        swap(tt[p].m1 , tt[p].m0);
        return ;
    }
    pushdown(p);
    int mid = (tt[p].l + tt[p].r) >> 1;
    if(l <= mid)
        updata(l, r, v, p << 1);
    if(r > mid)
        updata(l, r, v, p << 1 | 1);
    pushup(p);
}

int query(int l, int r, int p)
{
    if(l <= tt[p].l && r >= tt[p].r)
    {
        return tt[p].m0;
    }
    pushdown(p);
    int mid = (tt[p].l + tt[p].r) >> 1;
    int ans = 0;
    if(l <= mid)
        ans += query(l, r, p << 1);
    if(r > mid)
        ans += query(l, r, p << 1 | 1);
    return ans;
}
int main()
{
    int T;
    int cnt = 0;
    cin >> T;
    while(T--)
    {
        int n, q;
        scanf("%d%d", &n, &q);
        build(1, n, 1);
        printf("Case %d:\n", ++cnt);
        while(q--)
        {
            int t, x, y;
            scanf("%d%d%d", &t ,&x ,&y);
            if(t)
                printf("%d\n", query(x+1, y+1, 1));
            else
                updata(x+1, y+1, 1, 1);
        }
    }
    return 0;
}
时间: 2024-12-29 17:03:32

LightOJ 1135 - Count the Multiples of 3 线段树的相关文章

1135 - Count the Multiples of 3

  PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limit: 64 MB You have an array with n elements which is indexed from 0 to n - 1. Initially all elements are zero. Now you have to deal with two types of operations Increase the numbers b

ZOJ 1610 Count the Colors【题意+线段树区间更新&amp;&amp;单点查询】

任意门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610 Count the Colors Time Limit: 2 Seconds      Memory Limit: 65536 KB Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent

POJ - 2777——Count Color(懒标记线段树二进制)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 53639   Accepted: 16153 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

【bzoj3956】Count 单调栈+可持久化线段树

题目描述 输入 输出 样例输入 3 2 0 2 1 2 1 1 1 3 样例输出 0 3 题解 单调栈+可持久化线段树 本题是 bzoj4826 的弱化版(我为什么做题总喜欢先挑难的做QAQ) $k$对点对$(i,j)$有贡献,当且仅当$a_k=max(a_{i+1},a_{i+2},...,a_{r-1})$,且$a_k<a_i\&\&a_k<a_j$. 那么我们可以使用单调栈求出i左面第一个比它大的位置$lp[i]$,和右面第一个比它大的位置$rp[i]$,那么点对$(lp

FZU 2105 Digits Count(按位维护线段树)

[题目链接] http://acm.fzu.edu.cn/problem.php?pid=2105 [题目大意] 给出一个序列,数字均小于16,为正数,每次区间操作可以使得 1. [l,r]区间and一个数 2. [l,r]区间or一个数 3. [l,r]区间xor一个数 4. [l,r]区间查询和 操作数均为小于16的非负整数 [题解] 由于操作数很小,因此我们可以按位维护四棵线段树,表示二进制中的第i位, 对于and操作,只有当and的当前位为0时才对区间有影响,效果是将区间全部变为0, 对

FZU2105 Digits Count(按位建线段树)题解

题意: 给出区间与.或.异或\(x\)操作,还有询问区间和. 思路: 因为数比较小,我们给每一位建线段树,这样每次只要更新对应位的答案. 与\(0\)和或\(1\)相当于重置区间,异或\(1\)相当于翻转区间,那么设出两个\(lazy\)搞一下.注意父区间\(pushdown\)重置标记时,子区间的翻转标记要清空. 代码: #include <map> #include <set> #include <queue> #include <cmath> #inc

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

poj 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

LightOJ 1097 - Lucky Number 线段树

http://www.lightoj.com/volume_showproblem.php?problem=1097 题意:一个自然数序列,先去掉所有偶数项,在此基础上的序列的第二项为3,则删去所有3的倍数的元素,再是7……重复操作,最后问第n项的值 思路:使用线段树构造序列,对一个数进行标记是否已被删去,和为元素个数.由于样例给出了大小,所以很容易控制空间. /** @Date : 2016-12-05-19.34 * @Author : Lweleth ([email protected])