461C. Appleman and a Sheet of Paper(树状数组)

C. Appleman and a Sheet of Paper

time limit per test

2 seconds

memory limit per test

256 megabytes

Appleman has a very big sheet of paper. This sheet has a form of rectangle with dimensions 1 × n. Your task is help Appleman with folding of such a sheet. Actually, you need to perform q queries. Each query will have one of the following types:

  1. Fold the sheet of paper at position pi. After this query the leftmost part of the paper with dimensions 1 × pi must be above the rightmost part of the paper with dimensions 1 × ([current width of sheet] - pi).
  2. Count what is the total width of the paper pieces, if we will make two described later cuts and consider only the pieces between the cuts. We will make one cut at distance li from the left border of the current sheet of paper and the other at distance ri from the left border of the current sheet of paper.

Please look at the explanation of the first test example for better understanding of the problem.

Input

The first line contains two integers: n and q (1  ≤ n ≤ 105; 1 ≤ q ≤ 105) — the width of the paper and the number of queries.

Each of the following q lines contains one of the described queries in the following format:

  • "1 pi" (1 ≤ pi < [current width of sheet]) — the first type query.
  • "2 li ri" (0 ≤ li < ri ≤ [current width of sheet]) — the second type query.

Output

For each query of the second type, output the answer.

Sample test(s)

input

7 4
1 3
1 2
2 0 1
2 1 2

output

4
3

input

10 9
2 2 9
1 1
2 0 1
1 8
2 0 8
1 2
2 1 3
1 4
2 2 4

output

7
2
10
4
5

题意:给你一张1*n的纸片,有2种操作:(1)1 x,在x的地方将左半部分向左边折叠。(2)2 x y 求[x,y]区间的纸片厚度总和

思路:其实是一道模拟题,因为N的范围,和多次求区间和,明显应该用树状数组。。在折叠的过程中折叠后的纸片会变小。在1—N的线段上覆盖的长度也在减小,每次折叠完会多出一些没用的区间(想象一下不用将纸片前移到0,只是不断的折叠),所以当折叠过去后超过当前的右边界。。可以等效为将右边的向左折,相当于翻转了一次。。(不能向左折因为超出的部分会加上没用的区间的厚度)下次再进行折叠操作的时候就看成起始端在右边。。你可以设置标记。。2次翻转就恢复正常样子

代码:(参考别人的):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 100005;
int bit[maxn];
int n, q;
int lowbit(int x)
{
    return x & -x;
}
void add(int x, int y)
{
    while(x <= n)
    {
        bit[x] += y;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ans = 0;
    while(x > 0)
    {
        ans += bit[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    int t, p, x, y;
    scanf("%d%d", &n, &q);
    memset(bit, 0, sizeof(bit));
    for(int i = 1; i <= n; i++) add(i, 1);
    bool flag = 0;
    int l = 1, r = n;
    for(int i = 0; i < q; i++)
    {
        scanf("%d", &t);
        if(t == 1)
        {
            scanf("%d", &p);
            if(!flag) p = l + p;//根据纸片是否与正常翻转过来重新计算折纸点
            else p = r - p + 1;
            if(2 * p > r + l + 1)//右半部分小,向左边叠
            {
                for(int j = p; j <= r; j++)
                {
                    int u = getsum(j) - getsum(j - 1);//下标从0开始对树状数组处理时都要减1.下同
                    add(2 * p - j- 1, u);
                }
                r = p - 1;
                if(flag == 0) flag ^= 1;
            }
            else
            {
                for(int j = l; j < p; j++)
                {
                    int u = getsum(j) - getsum(j - 1);
                    add(2 * p - 1 - j, u);
                }
                l = p;
                if(flag == 1) flag ^= 1;
            }
        }
        else
        {
            scanf("%d%d", &x, &y);
            if(!flag)
            {
                x = l + x - 1;
                y = l + y - 1;
            }
            else
            {
                int t = x;
                x = r - y;
                y = r - t;
            }
            printf("%d\n", getsum(y) - getsum(x));
        }
    }
    return 0;
}

下面一种类似,还省去了标记:只用看L与R 的关系判断上次有没有翻转过

#include <cstdio>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
int tree[1<<20];
void add(int pos, int val)
{
    for (int i = pos; i<(1<<20); i = ((i) | (i + 1))) tree[i] += val;
}
int sum(int pos)
{
    int ans = 0;
    for (int i = pos; i>0; i = ((i)&(i - 1))) ans += tree[i - 1];
    return ans;
}
int get(int x)
{
    return sum(x + 1) - sum(x);
}
void update(int x, int val)
{
    add(x, val);
}
int sum(int L, int R)
{
    return sum(R) - sum(L);
}
int main()
{
    int N, Q, i, j;
    scanf("%d%d", &N, &Q);
    int L = 0, R = N;
    REP(i, N) update(i, 1);
    REP(j, Q)
    {
        int type;
        scanf("%d", &type);
        if (type == 1)
        {
            int p;
            scanf("%d", &p);
            int M;
            if (L < R) M = L + p;
            else M = L - p;
            if (L > R) swap(L, R);
            int w = min(M - L, R - M);
            int L2, R2;
            if (M - L <= R - M)
            {
                REP(i, w)
                {
                    int tmp = get(M - 1 - i);
                    update(M + i, tmp);
                }
                L2 = M;
                R2 = R;
            }
            else
            {
                REP(i, w)
                {
                    int tmp = get(M + i);
                    update(M - 1 - i, tmp);
                }
                L2 = M;
                R2 = L;
            }
            L = L2;
            R = R2;
        }
        else
        {
            int l, r;
            scanf("%d%d", &l, &r);
            int ans = 0;
            if (L < R) ans = sum(L + l, L + r);
            else ans = sum(L - r, L - l);
            printf("%d\n", ans);
        }
    }
}

时间: 2024-10-14 05:41:24

461C. Appleman and a Sheet of Paper(树状数组)的相关文章

Codeforces Round #263 (Div. 1) C. Appleman and a Sheet of Paper 树状数组暴力更新

C. Appleman and a Sheet of Paper Appleman has a very big sheet of paper. This sheet has a form of rectangle with dimensions 1 × n. Your task is help Appleman with folding of such a sheet. Actually, you need to perform q queries. Each query will have

Codeforces 461C Appleman and a Sheet of Paper(模拟)

题目链接:Codeforces 461C Appleman and a Sheet of Paper 题目大意:就是一个叠被子的过程,穿插着询问一段区间上被子的单位厚度. 解题思路:用前缀和数组模拟即可.因为对于折超过一半的处理为将令一半叠上来,所以需要变量记录当前被子的正反状态.处理好下标关系即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const

Codeforces 461C. Appleman and a Sheet of Paper

每次只把短的部分往长的部分折叠,直接用树状数组爆搞就可以了. 每次长度都缩小一些暴力的复杂度不是太高,启发式暴力???? C. Appleman and a Sheet of Paper time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a very big sheet of paper. This s

【2018.12.15】【考试总结】【模拟+逆序对+树状数组+贪心+multiset】爆零之旅

这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的QAQ 答题卡 [题目背景] 八月是个悲惨的月份.先不谈炎热的天气,对于新生来说,八月意味着军训: 而对于高二高三的同学来说,八月意味着开学考试.而考试就意味着改卷,改卷 也就意味着答题卡.不幸的是,学校读答题卡的机器的评分软件坏了,wyx 就被 老师要求写一个评分的程序. [问题描述] 软件需要读入学生的姓名.试题答案以及学生的答题卡信息. 学生姓名 学校的信息管理系统中存储了所有学生的姓名,一共 名学生.每个学生的 名字的组成只

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

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

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

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的