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; }