BUAA 1088 再也不会依赖任何人了

来源:互联网 发布:java做毕业设计难吗 编辑:程序博客网 时间:2024/05/20 10:54


北航校赛的一道题。。。

看到数据量就直接想到线段树实现了,但是区间修改的操作不是线性关系,而是对区间内的每个数进行平方,那就需要对线段树的节点进行类似于一种状态压缩的处理了。

因为结果是要对61求余的,所以一开始想到的就是每个节点保存60个值,分别代表对应数字在改区间内出现的次数,虽然空间复杂度勉强过的去,但是时间复杂度就难看了。。。。(囧,一个节点要计算60次跪了)然后就想到优化一下,如果该节点的区间范围小于61,就直接在此截止,下面直接就是个线性表,相当于线段树砍掉下面的一部分,补了个线性表,那么原来的线段树层数就变成log2(100000/61)≈11层,加一层线性表那么一次操作就是12*60=720次,乘个100000就是7200w,虽然题目时限8000ms,但这只是一颗10w节点的树的处理时间。。。所以还是跪。。。

然后就寻思着开始找规律,直接把1~60所有的值都循环处理一遍,其中存在4个环,3个环的长度为4,1个环的长度为2,(看了别人的题解才想到费马小定理可以直接得到6次平方操作==2次平方操作的结论【一口老血都喷在屏幕上】,数论没学好=.=)那就是任意一个数进行2次平方后就会进入一个4长度或者2长度的循环节中,那么对于每个节点只要保存6种情况(2种+4种(循环)的sum就可以了,对于较大的延迟标记lazy的处理是先减一个2再对循环节4求余,然后把2加回来,这样lazy就减小了。于是乎。。更新的问题就解决了。


#include <stdio.h>const int Mod = 61;const int MAXM = 110000;const int Size = 6;int L,R;struct P{int Now[MAXM<<2];int Lazy[MAXM<<2];int Sum[MAXM<<2][Size];void Pushup(int pos){int a=Now[pos<<1],b=Now[pos<<1|1];Now[pos]=0;for(int i=0;i<Size;i++){Sum[pos][i]=Sum[pos<<1][a]+Sum[pos<<1|1][b];a++;b++;if(a==Size)a=2;if(b==Size)b=2;}}void Pushdown(int pos){if(Lazy[pos]){Lazy[pos<<1]+=Lazy[pos];Lazy[pos<<1|1]+=Lazy[pos];if(Lazy[pos]>=2)Lazy[pos]=(Lazy[pos]-2&3)+2;while(Lazy[pos]){Now[pos<<1|1]++;Now[pos<<1]++;if(Now[pos<<1|1]==Size)Now[pos<<1|1]=2;if(Now[pos<<1]==Size)Now[pos<<1]=2;Lazy[pos]--;}}}void Build(int Left,int Right,int pos){Lazy[pos]=0;if(Left==Right){scanf("%d",Sum[pos]);*Sum[pos]%=Mod;for(int i=1;i<Size;i++){Sum[pos][i]=Sum[pos][i-1]*Sum[pos][i-1]%Mod;}Now[pos]=0;return;}int Mid=(Left+Right)>>1;Build(Left,Mid,pos<<1);Build(Mid+1,Right,pos<<1|1);Pushup(pos);}int Query(int Left,int Right,int pos){if(L<=Left&&Right<=R)return Sum[pos][Now[pos]];Pushdown(pos);int Mid=(Left+Right)>>1;int ans=0;if(L<=Mid)ans+=Query(Left,Mid,pos<<1);if(R>Mid)ans+=Query(Mid+1,Right,pos<<1|1);return ans;}void Updata(int Left,int Right,int pos){if(L<=Left&&Right<=R){Now[pos]++;if(Now[pos]==Size)Now[pos]=2;Lazy[pos]++;return;}Pushdown(pos);int Mid=(Left+Right)>>1;if(L<=Mid)Updata(Left,Mid,pos<<1);if(R>Mid)Updata(Mid+1,Right,pos<<1|1);Pushup(pos);}}Tree;int main(){int Ans;char Com;int Num,Quest;while(~scanf("%d %d",&Num,&Quest)){Tree.Build(1,Num,1);while(Quest--){scanf(" %c %d %d",&Com,&L,&R);if(Com=='Q'){Ans=Tree.Query(1,Num,1)%Mod;printf("%d\n",Ans*Ans%Mod);}else{Tree.Updata(1,Num,1);}}}}



中间把&运算的优先级记错了WA了好几发。。   卧槽这游戏简直难玩

0 0
原创粉丝点击