標籤:des os io ar strong for art 代碼 sp
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:
- 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).
- 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);
}
}
}
461C. Appleman and a Sheet of Paper(樹狀數組)