【NOIP2013模拟联考7】数列
2016-06-25 16:23
405 查看
Description
给出一个序列,每个数由一个二元组(a,b)表示,有4中操作1:把a值在l~r范围内的数乘上x再加上y
2:把b值在l~r范围内的数乘上x再加上y
3:询问a值在l~r范围内的数的和。
4:询问b值在l~r范围内的数的和。
n<=50000
Solution
写了一下午的常数优化,终于过掉了TAT具体来说,很容易想到第一个分块。我们用每个块维护原块和排过序的块,那么我们2操作修改的就是每个块中的连续一段。1操作所覆盖的块由于对应关系可以直接打标记,剩下的自己手动修改就好了。
那么连续的区间标记呢?总不能用线段树吧?
好吧,一开始我用的就是线段树。。。结果跑的和暴力分数一样(出题人良心大大滴坏TAT)
其实,我们可以使用分块套分块(分块大法好!)
区间标记也用一个块来维护。
然后?然后你就去打吧。。。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define N 50005 #define M 2500 #define S 50 using namespace std; const int mo=536870912; struct note{int v,w;}a ,b ; bool cmp(note x,note y) {return x.v<y.v;} int L[M],R[M],Len[M],l[M][S],r[M][S],sz[M],len[M][S],pos ,n,m,q,op,x,y,u,v; int Sum[M],Mul[M],Add[M],sum[M][S],mul[M][S],add[M][S],p ,ans,Mult,Plus; int get() { char ch;while (!isdigit(ch=getchar())); int o=ch-48;while (isdigit(ch=getchar())) o=o*10+ch-48; return o; } void make(int x) { sz[x]=Len[x]/S+((Len[x]%S)>0); fo(i,1,sz[x]) { l[x][i]=max(r[x][i-1]+1,L[x]); r[x][i]=min(l[x][i]+S,R[x]); len[x][i]=r[x][i]-l[x][i]+1; mul[x][i]=1; } } void Down(int x) { (Sum[x]*=Mul[x])+=Len[x]*Add[x]; fo(i,1,sz[x]) mul[x][i]*=Mul[x],(add[x][i]*=Mul[x])+=Add[x]; Mul[x]=1;Add[x]=0; } void down(int x,int y) { (sum[x][y]*=mul[x][y])+=len[x][y]*add[x][y]; fo(i,l[x][y],r[x][y]) (p[i]*=mul[x][y])+=add[x][y]; mul[x][y]=1;add[x][y]=0; } void Updata(int x) { Sum[x]=0; fo(i,1,sz[x]) Sum[x]+=sum[x][i]*mul[x][i]+len[x][i]*add[x][i]; } void updata(int x,int y) { sum[x][y]=0; fo(i,l[x][y],r[x][y]) sum[x][y]+=p[i]; } void change(int v,int x,int y) { fo(i,1,sz[v]) if (x<=b[l[v][i]].v&&b[r[v][i]].v<=y) mul[v][i]*=Mult,(add[v][i]*=Mult)+=Plus; else if (max(x,b[l[v][i]].v)<=min(y,b[r[v][i]].v)) { down(v,i); fo(j,l[v][i],r[v][i]) if (x<=b[j].v&b[j].v<=y) (p[j]*=Mult)+=Plus; updata(v,i); } Updata(v); } int query(int v,int x,int y) { int ans=0; fo(i,1,sz[v]) if (x<=b[l[v][i]].v&&b[r[v][i]].v<=y) ans+=sum[v][i]*mul[v][i]+len[v][i]*add[v][i]; else if (max(x,b[l[v][i]].v)<=min(y,b[r[v][i]].v)){ down(v,i); fo(j,l[v][i],r[v][i]) if (x<=b[j].v&&b[j].v<=y) ans+=p[j]; } return ans; } int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); n=get();q=get(); fo(i,1,n) b[i].v=get(),b[i].w=i; m=n/M+((n%M)>0); fo(i,1,m) { L[i]=R[i-1]+1;R[i]=min(L[i]+M,n);Len[i]=R[i]-L[i]+1; sort(b+L[i],b+R[i]+1,cmp);make(i);Mul[i]=1; fo(j,L[i],R[i]) pos[j]=i; } fo(i,1,n) a[b[i].w].w=i; for(;q;q--) { op=get();x=get();y=get();ans=0; if (op<=1) Mult=get(),Plus=get(); if (!op) { u=pos[x];v=pos[y]; if (u==v) { Down(u);fo(i,1,sz[u]) down(u,i); fo(i,x,y) (p[a[i].w]*=Mult)+=Plus; fo(i,1,sz[u]) updata(u,i);Updata(u); continue; } Down(u);fo(i,1,sz[u]) down(u,i); fo(i,x,R[u]) (p[a[i].w]*=Mult)+=Plus; fo(i,1,sz[u]) updata(u,i);Updata(u); Down(v);fo(i,1,sz[v]) down(v,i); fo(i,L[v],y) (p[a[i].w]*=Mult)+=Plus; fo(i,1,sz[v]) updata(v,i);Updata(v); fo(i,u+1,v-1) Mul[i]*=Mult,(Add[i]*=Mult)+=Plus; } else if (op==1) fo(i,1,m) Down(i),change(i,x,y); else if (op==2) { u=pos[x];v=pos[y]; if (u==v) { Down(u);fo(i,1,sz[u]) down(u,i); fo(i,x,y) ans+=p[a[i].w]; printf("%d\n",(ans%mo+mo)%mo); continue; } Down(u);fo(i,1,sz[u]) down(u,i); fo(i,x,R[u]) ans+=p[a[i].w]; Down(v);fo(i,1,sz[v]) down(v,i); fo(i,L[v],y) ans+=p[a[i].w]; fo(i,u+1,v-1) ans+=Sum[i]*Mul[i]+Len[i]*Add[i]; } else fo(i,1,m) Down(i),ans+=query(i,x,y); if (op>=2) printf("%d\n",(ans%mo+mo)%mo); } }
Ps:这是一个超时代码,其余优化留给读者自行思考。
相关文章推荐
- nginx日志查看goaccess安装使用
- 2014年北航机考题(推免)
- Valid Parentheses 合法括号
- js基本语法介绍
- android设置背景色为透明
- <<数字信号通信>>问题列表
- 一个简单的账号密码输入框
- 打好Android基础,实战中运用基础
- MySQL Having的使用方法
- iptables的地址取反操作
- 【每天一道leetcode】1:N-Queens
- 实验:基本的系统安全控制 实验环境 某公司新增了一台企业级服务器,已安装运行RHEL 6操作系统,由系统运维部、软件开发部、技术服务部共同使用。由于用户数量众多,且使用时间不固定,要求针对账号和
- preset 与编码速度和质量相关
- 使用React Native一年后的感受
- Android Studio 获取 sha1、MD5签名
- 在屏幕上输出以下图案: * *** ***** ******* ********* *********** ************* ********
- 6月份英语学习总结
- nginx之访问日志文件自动切割
- 默认勾选以太网不能够联网的问题
- 剑指offer-面试6:重建二叉树(二叉树前中后序遍历)