2633. [HZOI 2016] 数列操作e
★★★☆ 输入文件:rneaty.in
输出文件:rneaty.out
简单对比
时间限制:1 s 内存限制:128 MB
【题目描述】
一个长度为n的序列,一开始序列数的权值都是0,有m次操作
支持两种操作,
1 L R x,给区间[L,R]内,第一个数加x,第二个数加22⋅x,第三个数加32⋅x...第R-L+1个数加(R−L+1)2⋅x
2 L R 查询区间[L,R]内的权值和
每次询问的答案对264取模
【输入格式】
第一行两个数n,m,表示序列长度和操作次数
接下来m行,每行描述一个操作,有如下两种情况:
1 L R x,给区间[L,R]内,第一个数加x,第二个数加22⋅x,第三个数加32⋅x...第R-L+1个数加(R−L+1)2⋅x
2 L R 查询区间[L,R]内的权值和
【输出格式】
为了减少输出,你只需要输出所有答案对264取膜之后的异或和。
【样例输入】
5 5
1 3 4 1
2 1 5
2 2 2
1 3 3 1
1 2 4 1
【样例输出】
5
【提示】
对于10%的数据 n,m<=2000
对于30%的数据 n,m<=10000
对于100%的数据,n,m<=100000,1<=L<=R<=n,0<=x<=109
【来源】
一只名字很长的蒟蒻
线段树标记永久化QAQ
这一道题的方法就是先把题目中的那个式子拆开
就可以最终拆分成这样:i^2*x + i*2(1-L)*x +(L-1)^2*x
然后针对每一项 我们打一个lz标记
同时要先预处理出一些东东
比如第一项可以预处理出i^2
第二项可以预处理出i*2*(1-L)
第三项可以预处理出(L-1)^2//其实这个不需要预处理
然后我们把式子拆分开来后就简单多了
这里还有几个补充的知识点
1.unsigned long long 是自动对2^64取模
2.一定要注意类型 防止爆intQAQ 比如那个i^2 就要i*1ull*i才行 (否则就30分 )
代码如下
:
♪(^∇^*)
#include<bits/stdc++.h> #define maxn 100005 #define LL unsigned long long #define mid (l+r>>1) using namespace std; int n,m; int RT; int cnt;//标记 下标 int ls[maxn<<1],rs[maxn<<1]; LL lz0[maxn<<1],lz1[maxn<<1],lz2[maxn<<1]; LL sum[maxn<<1]; LL s1[maxn],s2[maxn]; void Build(int &rt,int l,int r) { if(!rt) rt=++cnt; if(l==r) return; Build(ls[rt],l,mid); Build(rs[rt],mid+1,r); } LL ans; void Add(int rt,int l,int r,int s,int t,LL x2,LL x1,LL x0) { if(s>r||t<l) return; if(s<=l&&r<=t) { lz2[rt]+=x2; lz1[rt]+=x1; lz0[rt]+=x0; sum[rt]=sum[ls[rt]]+sum[rs[rt]]+lz2[rt]*(s2[r]-s2[l-1])+lz1[rt]*(s1[r]-s1[l-1])+lz0[rt]*(r-l+1); return; } Add(ls[rt],l,mid,s,t,x2,x1,x0); Add(rs[rt],mid+1,r,s,t,x2,x1,x0); sum[rt]=sum[ls[rt]]+sum[rs[rt]]+lz2[rt]*(s2[r]-s2[l-1])+lz1[rt]*(s1[r]-s1[l-1])+lz0[rt]*(r-l+1); return; } LL Sum(int rt,int l,int r,int s,int t) { if(s>r||t<l) return 0; if(s<=l&&r<=t) return sum[rt]; int ll=max(l,s); int rr=min(r,t); return Sum(ls[rt],l,mid,s,t)+Sum(rs[rt],mid+1,r,s,t)+lz2[rt]*(s2[rr]-s2[ll-1])+lz1[rt]*(s1[rr]-s1[ll-1])+lz0[rt]*(rr-ll+1); } int main() { freopen("rneaty.in","r",stdin); freopen("rneaty.out","w",stdout); scanf("%d%d",&n,&m); Build(RT,1,n); for(int i=1;i<=n;i++) { s1[i]=s1[i-1]+i; s2[i]=s2[i-1]+i*1ull*i; } while(m--) { int opt,L,R; scanf("%d%d%d",&opt,&L,&R); if(opt==1) { LL x; scanf("%llu",&x); //i^2*x + i*2(1-L)*x +(L-1)^2*x //1^2 + 2^2 +3^2 +..+n^2 =n*(n+1)*(2n+1)/6 Add(1,1,n,L,R,x,x*2*(1ull-L),(L-1)*x*(L-1)) ; } else ans^=Sum(1,1,n,L,R); } printf("%llu ",ans); return 0; }