您的位置:首页 > 其它

【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:这是一个超时代码,其余优化留给读者自行思考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: