E. Appleman and a Sheet of Paper
题意:一张纸,有n个单位长度,有两种操作,一是从左往右折叠到指定位置,二是求一个区间内有多少个单位长度的纸。
思路:树状数组。操作一是区间更新,操作二是区间查询。区间更新做不到,只能对区间内每个点进行更新,区间更新需要O(q*n*log(n)),看似会超时,其实不然,因为可以折叠的程度是有限的,总复杂度实际上是O(n*log(n))。
还有个问题,如果像题目那样每次从左往右折叠,纸的范围会大大超过其长度,处理办法是根据折叠的位置,选择正向折叠还是反向折叠,这样纸张就不会跑出n的范围了。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define INF 1000000010
#define ll long long
#define max3(a,b,c) max(a,max(b,c))
#define MAXN 100010
using namespace std;
int n,Q;
int a[100010];
int c[100010];
inline int lowbit(int x){
return x&(-x);
}
inline int update(int x,int num){
while(x<=n){
c[x]+=num;
x+=lowbit(x);
}
}
inline int sum(int end){
int re=0;
while(end){
re+=c[end];
end-=lowbit(end);
}
return re;
}
int main(){
while(cin>>n>>Q){
int curlen=n;
int curs=1;
for(int i=1;i<=n;i++){
a[i]=1;
c[i]=lowbit(i);
}
bool b=true;
for(int q=0;q<Q;q++){
int type;
scanf("%d",&type);
if(type==1){
int p;
scanf("%d",&p);
bool b2=(p<=curlen/2);
if( !(b^b2) ){//正叠
if(!b2)p=curlen-p;
for(int i=0;i<p;i++){
update(curs+p+i,a[curs+p-i-1]);
update(curs+p-i-1,-a[curs+p-i-1]);
a[curs+p+i]+=a[curs+p-i-1];
a[curs+p-i-1]=0;
}
if(!b2)b=!b;
curs+=p;
curlen=max(p,curlen-p);
}else{
if(!b2)p=curlen-p;
for(int i=0;i<p;i++){
update(curs+curlen-1-(p+i),a[curs+curlen-1-(p-i-1)]);
update(curs+curlen-1-(p-i-1),-a[curs+curlen-1-(p-i-1)]);
a[curs+curlen-1-(p+i)]+=a[curs+curlen-1-(p-i-1)];
a[curs+curlen-1-(p-i-1)]=0;
}
if(!b2)b=!b;
curlen=max(p,curlen-p);
}
}else{
int l,r;
scanf("%d%d",&l,&r);
int ans=0;
if(b){
ans=sum(curs+r-1)-sum(curs+l-1);
}else{
ans=sum(curs+curlen-1-l)-sum(curs+curlen-r-1);
}
printf("%d\n",ans);
}
}
}
return 0;
}
本文介绍了一种使用树状数组解决纸张折叠问题的方法。通过正向或反向折叠减少纸张超出长度的问题,并详细阐述了如何利用树状数组进行区间更新和查询操作。
649

被折叠的 条评论
为什么被折叠?



