题解 P1198 【[JSOI2008]最大数】

斯德哥尔摩

2017-08-19 12:59:53

Solution

这题就是一个 裸的线段树,但 线段树 每个节点存 一段区间中的最大值, 这样就可以保证每次询问都不用再扫一遍数据,否则除了 TLE 就是 30%AC 。。。 话说 线段树 除了常数大了之外好像没有什么缺点。。。(因为我只会写线段树,吃枣药丸) **不要复制代码!不要复制代码!!不要复制代码!!!重要的事情说3遍!** 附代码(缩进不喜勿喷): ```cpp #include<iostream> #include<algorithm> #include<stdio.h> #define LSON rt<<1 #define RSON rt<<1|1//方便实用的宏。。。 #define max(a,b) a>b?a:b//STL的函数比手写的慢,所以为了减小被卡常数的几率,手写。。。 #define MAXN 200005 using namespace std; int m,d; long long t=0,a[MAXN<<2];//线段树 的空间是 原数据 的 4 倍,这是一定的 inline long long read(){//弱弱的读入优化,但好像没有什么用。。。防止被卡常吧 long long date=0,w=1;char c=0; while(c!='-'&&(c<'0'||c>'9'))c=getchar(); if(c=='-'){w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void pushup(int rt){ a[rt]=max(a[LSON],a[RSON]);//每个节点存 区间最大值 } void update(int l,int r,int rt,int x,long long y){//针对题目的输入,建树与插入的合体。。。 int mid; if(l==r){ a[rt]=y;//叶子结点时赋 区间最大值 return; } mid=l+r>>1;//位运算,经验靠诉我们 >>1 比 /2 快很多。。。 if(x<=mid)update(l,mid,LSON,x,y); else update(mid+1,r,RSON,x,y);//分 左子树 与 右子树 建立 pushup(rt);//一定不要忘记这句话!!!很重要!!! } long long query(int l,int r,int rt,int x,int y){ int mid; long long ans=-2147483647;//注意,千万不要设成 0 ,当初我提交3次,2次被卡 if(x<=l&&y>=r)//出了范围就返回区间最大值 return a[rt]; mid=l+r>>1; if(x<=mid)ans=max(ans,query(l,mid,LSON,x,y)); if(mid<y)ans=max(ans,query(mid+1,r,RSON,x,y));//还是 左子树 与 右子树 处理 return ans;//不同上!!!一定要返回答案!!! } int main(){ int x,s=0; char c[2]; m=read();d=read(); for(int i=1;i<=m;i++){ scanf("%s",c);//每行首字为 字符,为避免读入 回车符 ‘\n’ 或者 "\r\n",用 %s ,这是一个很实用的东东。。。 if(c[0]=='A'){//分情况处理。。。 x=read(); s++; x=(x+t)%d; update(1,m,1,s,x);//询问范围是 1 到 m } if(c[0]=='Q'){ x=read(); t=query(1,m,1,s-x+1,s);//这里只是为了 t 能在下一次询问时使用 printf("%lld\n",t);//注意,t 为 long long,不然会炸。。。 } } return 0;//收尾。。。 } ```