文章目录
总览:
优雅的暴力……
按照一定的模式乱搞……
分块九题+蒲公英+弹飞绵羊
先放神仙博客:传送门
模式:
预处理:
块的大小的
m
m
m,维护数据的
v
a
l
val
val和记录块数的
b
e
be
be
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++) belong[i]=(i-1)/m+1;
维护操作
O
(
n
)
O(\sqrt n)
O(n):
区间修改标记
t
a
g
tag
tag
如果左右端点在同一块,暴力维护。(块的大小小于
n
\sqrt n
n,时间复杂度为
O
(
n
)
O(\sqrt n)
O(n))
其他,暴力维护左右块,区间维护中间块。(左右块的大小小于
n
\sqrt n
n,中间块的个数小于
n
\sqrt n
n,时间复杂度为
O
(
n
)
O(\sqrt n)
O(n))
inline void add(int l,int r,int v){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++) val[i]=v;
return;
}
for(int i=l;belong[i]==belong[l];i++)
val[i]=v;
for(int i=belong[l]+1;i<=belong[r]-1;i++)
tag[i]=v;
for(int i=r;belong[i]==belong[r];i--)
val[i]=v;
}
查询操作
O
(
n
)
O(\sqrt n)
O(n):
同维护操作。
T1 #6277. 数列分块入门 1
#6277. 数列分块入门 1
题意:区间加,单点查
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=5e4+5;
int n,m;
int val[A];
int tag[A],belong[A];
inline void add(int l,int r,int v){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++) val[i]+=v;
return;
}
for(int i=l;belong[i]==belong[l];i++)
val[i]+=v;
for(int i=belong[l]+1;i<=belong[r]-1;i++)
tag[i]+=v;
for(int i=r;belong[i]==belong[r];i--)
val[i]+=v;
}
inline int qurey(int x){
return val[x]+tag[belong[x]];
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++) belong[i]=(i-1)/m+1;
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) add(l,r,c);
else printf("%d\n",qurey(r));
}
return 0;
}
T2 #6278. 数列分块入门 2
#6278. 数列分块入门 2
题意:区间加,区间查询个数
思路:保证块内有序,二分查找
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=5e4+5;
int n,m;
int val[A];
int tag[A],belong[A];
vector <int> s[500];
inline void reset(int be){
s[be].clear();
for(int i=(be-1)*m+1;i<=min(be*m,n);i++)
s[be].push_back(val[i]);
sort(s[be].begin(),s[be].end());
}
inline void add(int l,int r,int v){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
val[i]+=v;
reset(belong[l]);
return;
}
for(int i=l;belong[i]==belong[l];i++)
val[i]+=v;
reset(belong[l]);
for(int i=belong[l]+1;i<=belong[r]-1;i++)
tag[i]+=v;
for(int i=r;belong[i]==belong[r];i--)
val[i]+=v;
reset(belong[r]);
}
inline int qurey(int l,int r,int v){
int ans=0;
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
if(val[i]+tag[belong[i]]<v) ans++;
return ans;
}
for(int i=l;belong[i]==belong[l];i++)
if(val[i]+tag[belong[i]]<v) ans++;
for(int i=belong[l]+1;i<=belong[r]-1;i++)
ans+=lower_bound(s[i].begin(),s[i].end(),v-tag[i])-s[i].begin();
for(int i=r;belong[i]==belong[r];i--)
if(val[i]+tag[belong[i]]<v) ans++;
return ans;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/m+1;
s[belong[i]].push_back(val[i]);
}
for(int i=1;i<=n;i+=m)
sort(s[belong[i]].begin(),s[belong[i]].end());
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) add(l,r,c);
else printf("%d\n",qurey(l,r,c*c));
}
return 0;
}
T3 #6279. 数列分块入门 3
#6279. 数列分块入门 3
题意:区间加,求前驱
思路:保证块内有序,二分查找
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
int n,m;
int val[A];
int belong[A],tag[A];
vector <int> s[500];
inline void reset(int be){
s[be].clear();
for(int i=m*(be-1)+1;i<=min(m*be,n);i++){
s[be].push_back(val[i]+tag[be]);
val[i]+=tag[be];
}
tag[be]=0;
sort(s[be].begin(),s[be].end());
return;
}
inline void add(int l,int r,int v){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
val[i]+=v;
reset(belong[l]);
return;
}
for(int i=l;belong[i]==belong[l];i++)
val[i]+=v;
reset(belong[l]);
for(int i=belong[l]+1;i<=belong[r]-1;i++)
tag[i]+=v;
for(int i=r;belong[i]==belong[r];i--)
val[i]+=v;
reset(belong[r]);
return;
}
inline int qurey(int l,int r,int v){
int ans=-1;
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
if(val[i]+tag[belong[i]]<v) ans=max(ans,val[i]+tag[belong[i]]);
return ans;
}
for(int i=l;belong[i]==belong[l];i++)
if(val[i]+tag[belong[i]]<v) ans=max(ans,val[i]+tag[belong[i]]);
for(int i=belong[l]+1;i<=belong[r]-1;i++){
if(s[i].front()>=v-tag[i]) continue;
if(s[i].back()<v-tag[i]){
ans=max(ans,s[i].back()+tag[i]);
continue;
}
int w=lower_bound(s[i].begin(),s[i].end(),v-tag[i])-s[i].begin()-1;
ans=max(ans,s[i][w]+tag[i]);
}
for(int i=r;belong[i]==belong[r];i--)
if(val[i]+tag[belong[i]]<v) ans=max(ans,val[i]+tag[belong[i]]);
return ans;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/m+1;
s[belong[i]].push_back(val[i]);
}
for(int i=1;i<=n;i+=m)
sort(s[belong[i]].begin(),s[belong[i]].end());
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(opt) printf("%lld\n",qurey(l,r,c));
if(!opt) add(l,r,c);
}
return 0;
}
T4 #6280. 数列分块入门 4
#6280. 数列分块入门 4
题意:区间加,区间和
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=5e4+5;
int n,m;
int val[A];
int be[A],tag[A];
int sum[A];
inline void add(int l,int r,int v){
if(be[l]==be[r]){
for(int i=l;i<=r;i++){
val[i]+=v;
sum[be[i]]+=v;
}
return;
}
for(int i=l;be[i]==be[l];i++){
val[i]+=v;
sum[be[i]]+=v;
}
for(int i=be[l]+1;i<=be[r]-1;i++){
tag[i]+=v;
sum[i]+=m*v;
}
for(int i=r;be[i]==be[r];i--){
val[i]+=v;
sum[be[i]]+=v;
}
return;
}
inline int qurey(int l,int r,int mod){
int ans=0;
if(be[l]==be[r]){
for(int i=l;i<=r;i++)
ans=(ans+val[i]+tag[be[i]])%mod;
return ans;
}
for(int i=l;be[i]==be[l];i++)
ans=(ans+val[i]+tag[be[i]])%mod;
for(int i=be[l]+1;i<=be[r]-1;i++)
ans=(ans+sum[i])%mod;
for(int i=r;be[i]==be[r];i--)
ans=(ans+val[i]+tag[be[i]])%mod;
return ans%mod;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++){
be[i]=(i-1)/m+1;
sum[be[i]]+=val[i];
}
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) add(l,r,c);
if(opt) printf("%lld\n",qurey(l,r,c+1));
}
return 0;
}
T5 #6281. 数列分块入门 5
#6281. 数列分块入门 5
题意:区间开方,区间求和
思路:发现
0
,
1
0,1
0,1开方后不变,每一个数至多开方
31
31
31次。将数全为
0
,
1
0,1
0,1的区间打标记即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=5e4+5;
int n,m;
int val[A];
int be[A],sum[A];
bool tag[A];
inline void change(int x){
if(tag[x]) return;
int l=(x-1)*m+1,r=x*m;
bool bz=0;
for(int i=l;i<=r;i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
if(val[i]!=1&&val[i]!=0) bz=1;
}
if(!bz) tag[be[l]]=1;
}
inline void sq(int l,int r){
if(be[l]==be[r]){
if(tag[be[l]]) return;
for(int i=l;i<=r;i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
return;
}
if(!tag[be[l]])
for(int i=l;be[i]==be[l];i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
for(int i=be[l]+1;i<=be[r]-1;i++)
change(i);
if(!tag[be[r]])
for(int i=r;be[i]==be[r];i--){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
return;
}
inline int qurey(int l,int r){
int ans=0;
if(be[l]==be[r]){
for(int i=l;i<=r;i++)
ans+=val[i];
return ans;
}
for(int i=l;be[i]==be[l];i++)
ans+=val[i];
for(int i=be[l]+1;i<=be[r]-1;i++)
ans+=sum[i];
for(int i=r;be[i]==be[r];i--)
ans+=val[i];
return ans;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++)
val[i]=in;
for(int i=1;i<=n;i++){
be[i]=(i-1)/m+1;
sum[be[i]]+=val[i];
}
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) sq(l,r);
else printf("%lld\n",qurey(l,r));
}
return 0;
}
T6 #6282. 数列分块入门 6
#6282. 数列分块入门 6
题意:单点插入,单点询问
思路:发现某个块过大后整体重建。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
int n,m;
int val[A],be[A];
vector <int> s[500];
inline void rebuild(){
int id=0,num=0;
while(!s[id+1].empty()){
id++;
for(int y=0;y<s[id].size();y++)
val[++num]=s[id][y];
s[id].clear();
}
m=sqrt(num);
for(int i=1;i<=num;i++){
be[i]=(i-1)/m+1;
s[be[i]].push_back(val[i]);
}
return;
}
inline void putin(int w,int v){
int id=0,num=0;
while(num+s[id+1].size()<w){
id++;
num+=s[id].size();
}
id++;
s[id].insert(w-num-1+s[id].begin(),v);
if(s[id].size()>=20*m) rebuild();
return;
}
inline int qurey(int w){
int id=0,num=0;
while(num+s[id+1].size()<w){
id++;
num+=s[id].size();
}
id++;
return s[id][w-num-1];
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++)
val[i]=in;
for(int i=1;i<=n;i++){
be[i]=(i-1)/m+1;
s[be[i]].push_back(val[i]);
}
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) putin(l,r);
if(opt) printf("%d\n",qurey(r));
}
return 0;
}
T7 #6283. 数列分块入门 7
#6283. 数列分块入门 7
题意:区间乘,区间加,单点询问
思路:乘法优先(见线段树2)
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
const int mod=10007;
int n,m;
int val[A],be[A];
struct Block{
int add,mul;
}p[A];
inline void pushdown(int id){
for(int i=(id-1)*m+1;i<=min(n,id*m);i++)
val[i]=((val[i]*p[id].mul)%mod+p[id].add)%mod;
p[id].mul=1;
p[id].add=0;
return;
}
inline void add(int l,int r,int v){
if(be[l]==be[r]){
pushdown(be[l]);
for(int i=l;i<=r;i++)
val[i]=(val[i]+v)%mod;
return;
}
pushdown(be[l]);
for(int i=l;be[i]==be[l];i++)
val[i]=(val[i]+v)%mod;
for(int i=be[l]+1;i<=be[r]-1;i++)
p[i].add=(p[i].add+v)%mod;
pushdown(be[r]);
for(int i=r;be[i]==be[r];i--)
val[i]=(val[i]+v)%mod;
return;
}
inline void mul(int l,int r,int v){
if(be[l]==be[r]){
pushdown(be[l]);
for(int i=l;i<=r;i++)
val[i]=(val[i]*v)%mod;
return;
}
pushdown(be[l]);
for(int i=l;be[i]==be[l];i++)
val[i]=(val[i]*v)%mod;
for(int i=be[l]+1;i<=be[r]-1;i++){
p[i].add=(p[i].add*v)%mod;
p[i].mul=(p[i].mul*v)%mod;
}
pushdown(be[r]);
for(int i=r;be[i]==be[r];i--)
val[i]=(val[i]*v)%mod;
return;
}
inline int qurey(int w){
return (val[w]*p[(w-1)/m+1].mul%mod+p[(w-1)/m+1].add)%mod;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++)
be[i]=(i-1)/m+1;
for(int i=1;i<=n;i+=m)
p[be[i]].mul=1;
for(int i=1;i<=n;i++){
int opt=in,l=in,r=in,c=in;
if(!opt) add(l,r,c);
if(opt==1) mul(l,r,c);
if(opt==2) printf("%lld\n",qurey(r)%mod);
}
return 0;
}
T8 #6284. 数列分块入门 8
#6284. 数列分块入门 8
题意:区间查,区间改
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
int n,m;
int val[A];
int be[A],tag[A];
inline void reset(int b){
if(tag[b]==-1) return;
for(int i=(b-1)*m+1;i<=b*m;i++)
val[i]=tag[b];
tag[b]=-1;
return;
}
inline int work(int l,int r,int c){
int ans=0;
if(be[l]==be[r]){
reset(be[l]);
for(int i=l;i<=r;i++)
if(val[i]==c) ans++;
else val[i]=c;
return ans;
}
reset(be[l]),reset(be[r]);
for(int i=l;be[i]==be[l];i++)
if(val[i]==c) ans++;
else val[i]=c;
for(int i=r;be[i]==be[r];i--)
if(val[i]==c) ans++;
else val[i]=c;
for(int i=be[l]+1;i<=be[r]-1;i++){
if(tag[i]!=-1){
if(tag[i]!=c) tag[i]=c;
else ans+=m;
}
else{
for(int j=(i-1)*m+1;j<=i*m;j++)
if(val[j]==c) ans++;
else val[j]=c;
tag[i]=c;
}
}
return ans;
}
signed main(){
memset(tag,-1,sizeof(tag));
n=in;m=sqrt(n);
for(int i=1;i<=n;i++)
val[i]=in;
for(int i=1;i<=n;i++)
be[i]=(i-1)/m+1;
for(int i=1;i<=n;i++){
int l=in,r=in,c=in;
printf("%d\n",work(l,r,c));
}
return 0;
}
T9 #6285. 数列分块入门 9
#6285. 数列分块入门 9
题意:查询区间众数
思路:见
T
12
蒲
公
英
T12蒲公英
T12蒲公英
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
const int B=600;
int n,m;
int val[A],a[A],maxx;
int be[A];
int s[B][A],p[B][B];
int t[A];
vector <int> w;
inline void lsh(){
sort(a+1,a+1+n);
int len=unique(a+1,a+1+n)-(a+1);
for(int i=1;i<=n;i++){
val[i]=lower_bound(a+1,a+1+len,val[i])-a;
maxx=max(maxx,val[i]);
}
return;
}
inline void prepare(){
for(int i=1;i<=n;i++)
s[be[i]][val[i]]++;
for(int i=1;i<=be[n];i++)
for(int j=1;j<=maxx;j++)
s[i][j]+=s[i-1][j];
for(int i=1;i<=be[n];i++)
for(int j=1;j<=be[n];j++){
int res=1e9,num=0;
for(int k=(j-1)*m+1;k<=j*m;k++){
if(s[j][val[k]]-s[i-1][val[k]]>num){
res=val[k];
num=s[j][val[k]]-s[i-1][val[k]];
}
if(s[j][val[k]]-s[i-1][val[k]]==num&&val[k]<res)
res=val[k];
}
if(i==j){
p[i][j]=res;
continue;
}
int k=p[i][j-1];
if(s[j][k]-s[i-1][k]>num){
res=k;
num=s[j][k]-s[i-1][k];
}
if(s[j][k]-s[i-1][k]==num&&k<res)
res=k;
p[i][j]=res;
}
return;
}
inline void clean(){
for(int i=0;i<w.size();i++)
t[w[i]]=0;
w.clear();
return;
}
inline int qurey(int l,int r){
clean();
int res=1e9,num=0;
if(be[l]==be[r]){
for(int i=l;i<=r;i++){
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
w.push_back(val[i]);
}
return res;
}
for(int i=l;be[i]==be[l];i++){
if(!t[val[i]]) t[val[i]]+=(s[be[r]-1][val[i]]-s[be[l]][val[i]]);
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
w.push_back(val[i]);
}
for(int i=r;be[i]==be[r];i--){
if(!t[val[i]]) t[val[i]]+=(s[be[r]-1][val[i]]-s[be[l]][val[i]]);
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
w.push_back(val[i]);
}
if(be[l]==be[r]-1) return res;
int k=p[be[l]+1][be[r]-1];
if(t[k]) return res;
t[k]+=(s[be[r]-1][k]-s[be[l]][k]);
if(t[k]>num){
res=k;
num=t[k];
}
if(t[k]==num&&k<res)
res=k;
w.push_back(k);
return res;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=a[i]=in;
for(int i=1;i<=n;i++) be[i]=(i-1)/m+1;
lsh();
prepare();
for(int i=1;i<=n;i++){
int l=in,r=in;
printf("%d\n",a[qurey(l,r)]);
}
return 0;
}
T10 P4145 上帝造题的七分钟2 / 花神游历各国
P4145 上帝造题的七分钟2 / 花神游历各国
就是
T
5
T5
T5……
(双倍快乐)
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
int n,m,q;
int val[A];
int be[A],sum[A];
bool tag[A];
inline void change(int x){
if(tag[x]) return;
int l=(x-1)*m+1,r=x*m;
bool bz=0;
for(int i=l;i<=r;i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
if(val[i]!=1&&val[i]!=0) bz=1;
}
if(!bz) tag[be[l]]=1;
}
inline void sq(int l,int r){
if(be[l]==be[r]){
if(tag[be[l]]) return;
for(int i=l;i<=r;i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
return;
}
if(!tag[be[l]])
for(int i=l;be[i]==be[l];i++){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
for(int i=be[l]+1;i<=be[r]-1;i++)
change(i);
if(!tag[be[r]])
for(int i=r;be[i]==be[r];i--){
int v=sqrt(val[i]);
sum[be[i]]-=val[i]-v;
val[i]=v;
}
return;
}
inline int qurey(int l,int r){
int ans=0;
if(be[l]==be[r]){
for(int i=l;i<=r;i++)
ans+=val[i];
return ans;
}
for(int i=l;be[i]==be[l];i++)
ans+=val[i];
for(int i=be[l]+1;i<=be[r]-1;i++)
ans+=sum[i];
for(int i=r;be[i]==be[r];i--)
ans+=val[i];
return ans;
}
signed main(){
n=in;m=sqrt(n);
for(int i=1;i<=n;i++)
val[i]=in;
for(int i=1;i<=n;i++){
be[i]=(i-1)/m+1;
sum[be[i]]+=val[i];
}
q=in;
for(int i=1;i<=q;i++){
int opt=in,l=in,r=in;
if(l>r) swap(l,r);
if(!opt) sq(l,r);
else printf("%lld\n",qurey(l,r));
}
return 0;
}
然而还可以用线段树……
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
#define lch p<<1
#define rch p<<1|1
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=1e5+5;
int n,q;
int val[A];
struct Tree{
int l,r,max,sum;
}tree[4*A];
inline void pushup(int p){
tree[p].max=max(tree[lch].max,tree[rch].max);
tree[p].sum=tree[lch].sum+tree[rch].sum;
return;
}
inline void build(int p,int l,int r){
tree[p].l=l,tree[p].r=r;
if(l==r){
tree[p].max=tree[p].sum=val[l];
return;
}
int mid=(l+r)>>1;
build(lch,l,mid),build(rch,mid+1,r);
pushup(p);
return;
}
inline void sq(int p,int l,int r){
if(tree[p].l==tree[p].r){
tree[p].max=sqrt(tree[p].max);
tree[p].sum=tree[p].max;
return;
}
if(tree[p].max<=1) return;
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid) sq(lch,l,r);
if(r>=mid+1) sq(rch,l,r);
pushup(p);
return;
}
inline int qurey(int p,int l,int r){
if(tree[p].l>=l&&tree[p].r<=r) return tree[p].sum;
int ans=0;
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid) ans+=qurey(lch,l,r);
if(r>=mid+1) ans+=qurey(rch,l,r);
return ans;
}
signed main(){
n=in;
for(int i=1;i<=n;i++) val[i]=in;
build(1,1,n);
q=in;
for(int i=1;i<=q;i++){
int k=in,l=in,r=in;
if(l>r) swap(l,r);
if(!k) sq(1,l,r);
else printf("%lld\n",qurey(1,l,r));
}
return 0;
}
T11 P2801 教主的魔法
P2801 教主的魔法
类似
T
2
T2
T2……
(双倍快乐
×
2
\times2
×2)
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline char ch(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=ch();!isdigit(x);x=ch()) if(x=='-') f=-1;
for( ;isdigit(x);x=ch()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e6+5;
int n,q,m;
int val[A];
int tag[A],belong[A];
vector <int> s[1500];
char opt;
inline void reset(int be){
s[be].clear();
for(int i=(be-1)*m+1;i<=min(be*m,n);i++)
s[be].push_back(val[i]+tag[be]);
tag[be]=0;
sort(s[be].begin(),s[be].end());
}
inline void add(int l,int r,int v){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
val[i]+=v;
reset(belong[l]);
return;
}
for(int i=l;belong[i]==belong[l];i++)
val[i]+=v;
reset(belong[l]);
for(int i=belong[l]+1;i<=belong[r]-1;i++)
tag[i]+=v;
for(int i=r;belong[i]==belong[r];i--)
val[i]+=v;
reset(belong[r]);
}
inline int qurey(int l,int r,int v){
int ans=0;
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)
if(val[i]+tag[belong[i]]>=v) ans++;
return ans;
}
for(int i=l;belong[i]==belong[l];i++)
if(val[i]+tag[belong[i]]>=v) ans++;
for(int i=belong[l]+1;i<=belong[r]-1;i++)
ans+=(s[i].end()-lower_bound(s[i].begin(),s[i].end(),v-tag[i]));
for(int i=r;belong[i]==belong[r];i--)
if(val[i]+tag[belong[i]]>=v) ans++;
return ans;
}
signed main(){
n=in,q=in;m=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/m+1;
s[belong[i]].push_back(val[i]);
}
for(int i=1;i<=n;i+=m)
sort(s[belong[i]].begin(),s[belong[i]].end());
for(int i=1;i<=q;i++){
opt=ch();
while(opt!='A'&&opt!='M') opt=ch();
int l=in,r=in,c=in;
if(opt=='M') add(l,r,c);
else printf("%d\n",qurey(l,r,c));
}
return 0;
}
T12 P4168 [Violet]蒲公英
题目背景
亲爱的哥哥:
你在那个城市里面过得好吗?
我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫
「
绝
望
」
「绝望」
「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……
最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!
哥哥你要快点回来哦!
爱你的妹妹
V
i
o
l
e
t
Violet
Violet
A
z
u
r
e
Azure
Azure 读完这封信之后微笑了一下。
“蒲公英吗……”
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为n的序列
(
a
1
,
a
2
.
.
a
n
)
(a_1,a_2..a_n)
(a1,a2..an),其中
a
i
a_i
ai为一个正整数,表示第i棵蒲公英的种类编号。
而每次询问一个区间
[
l
,
r
]
[l,r]
[l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
注意,你的算法必须是在线的!
输入格式
第一行两个整数
n
,
m
n,m
n,m,表示有
n
n
n株蒲公英,
m
m
m 次询问。
接下来一行
n
n
n个空格分隔的整数
a
i
a_i
ai,表示蒲公英的种类
再接下来
m
m
m行每行两个整数
l
0
,
r
0
l_0,r_0
l0,r0,我们令上次询问的结果为
x
x
x(如果这是第一次询问,则
x
=
0
x=0
x=0)。
令
l
=
(
l
0
+
x
−
1
)
m
o
d
n
+
1
,
r
=
(
r
0
+
x
−
1
)
m
o
d
n
+
1
l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n + 1
l=(l0+x−1)modn+1,r=(r0+x−1)modn+1,如果
l
>
r
l>r
l>r,则交换
l
,
r
l,r
l,r 。
最终的询问区间为
[
l
,
r
]
[l,r]
[l,r]。
输出格式
输出
m
m
m行。每行一个整数,表示每次询问的结果。
输入输出样例
输入
6 3
1 2 3 2 1 2
1 5
3 6
1 5
输出
1
2
1
说明/提示
对于 20% 的数据,保证
1
≤
n
,
m
≤
3000
1\le n,m \le3000
1≤n,m≤3000。
对于 100% 的数据,保证
1
≤
n
≤
40000
,
1
≤
m
≤
50000
,
1
≤
a
i
≤
1
0
9
1\le n \le 40000,1\le m \le 50000,1\le a_i \le 10^9
1≤n≤40000,1≤m≤50000,1≤ai≤109。
分块重头戏……
一道黑题……
思路:
因为
n
≤
40000
,
a
i
≤
1
0
9
n\le 40000,a_i\le 10^9
n≤40000,ai≤109,所以离散化。
预处理两个数组:
s
[
i
]
[
j
]
s[i][j]
s[i][j]为第
i
i
i块中
j
j
j出现的次数。
p
[
i
]
[
j
]
p[i][j]
p[i][j]为第
i
i
i块到第
j
j
j块的众数。
发现区间 [ l , r ] [l,r] [l,r]的众数属于中间整块的众数和散块中的数的并集。那么统计这些数的个数 ( ≤ 2 × n + 1 ) (\le 2\times \sqrt n +1) (≤2×n+1)即可。
统计数的个数(用桶统计):
散块暴力扫描,整块类似前缀和,
O
(
1
)
O(1)
O(1)查询。
预处理:
s
[
i
]
[
j
]
s[i][j]
s[i][j](时间复杂度
O
(
n
)
O(n)
O(n)):扫一遍,求前缀和。
p
[
i
]
[
j
]
p[i][j]
p[i][j](时间复杂度
O
(
n
n
)
O(n\sqrt n)
O(nn)):
p
[
i
]
[
j
]
p[i][j]
p[i][j]的范围为
p
[
i
]
[
j
−
1
]
p[i][j-1]
p[i][j−1]与第
j
j
j块中出现的数的并集。
两成循环枚举
i
,
j
i,j
i,j,一层循环枚举第
j
j
j块中出现的数,通过
s
s
s数组求出现次数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline char ch(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=ch();!isdigit(x);x=ch()) if(x=='-') f=-1;
for( ;isdigit(x);x=ch()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=5e4+5;
const int B=1e3+5;
int n,m,blo;
int val[A],a[A],maxx;
int be[A];
int p[B][B];
int s[B][A];
int before,l,r;
int t[A];
vector <int> clean;
inline void lsh(){
sort(a+1,a+1+n);
int len=unique(a+1,a+1+n)-(a+1);
for(int i=1;i<=n;i++){
val[i]=lower_bound(a+1,a+1+len,val[i])-a;
maxx=max(maxx,val[i]);
}
return;
}
inline void prepare(){
for(int i=1;i<=n;i++)
s[be[i]][val[i]]++;
for(int i=1;i<=be[n];i++)
for(int j=1;j<=maxx;j++)
s[i][j]+=s[i-1][j];
for(int i=1;i<=be[n];i++)
for(int j=i;j<=be[n];j++){
int res=1e9,num=0;
for(int k=(j-1)*blo+1;k<=j*blo;k++){
if(s[j][val[k]]-s[i-1][val[k]]>num){
res=val[k];
num=s[j][val[k]]-s[i-1][val[k]];
}
if(s[j][val[k]]-s[i-1][val[k]]==num&&val[k]<res)
res=val[k];
}
if(i!=j){
int k=p[i][j-1];
if(s[j][k]-s[i-1][k]>num){
res=k;
num=s[j][k]-s[i-1][k];
}
if(s[j][k]-s[i-1][k]==num&&k<res)
res=k;
}
p[i][j]=res;
}
return;
}
inline int qurey(int l,int r){
if(!clean.empty()){
for(int i=0;i<clean.size();i++)
t[clean[i]]=0;
clean.clear();
}
int res=1e9,num=0;
if(be[l]==be[r]){
for(int i=l;i<=r;i++){
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
clean.push_back(val[i]);
}
return res;
}
for(int i=l;be[i]==be[l];i++){
if(!t[val[i]]) t[val[i]]+=(s[be[r]-1][val[i]]-s[be[l]][val[i]]);
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
clean.push_back(val[i]);
}
for(int i=r;be[i]==be[r];i--){
if(!t[val[i]]) t[val[i]]+=(s[be[r]-1][val[i]]-s[be[l]][val[i]]);
t[val[i]]++;
if(t[val[i]]>num){
res=val[i];
num=t[val[i]];
}
if(t[val[i]]==num&&val[i]<res)
res=val[i];
clean.push_back(val[i]);
}
if(be[l]==be[r]-1) return res;
int k=p[be[l]+1][be[r]-1];
if(t[k]) return res;
t[k]+=(s[be[r]-1][k]-s[be[l]][k]);
if(t[k]>num){
res=k;
num=t[k];
}
if(t[k]==num&&k<res)
res=k;
clean.push_back(k);
return res;
}
signed main(){
n=in,m=in;blo=sqrt(n);
for(int i=1;i<=n;i++) val[i]=a[i]=in;
for(int i=1;i<=n;i++) be[i]=(i-1)/blo+1;
lsh();
prepare();
for(int i=1;i<=m;i++){
l=in,r=in;
l=(l+before-1)%n+1,r=(r+before-1)%n+1;
if(l>r) swap(l,r);
printf("%d\n",before=a[qurey(l,r)]);
}
return 0;
}
T13 P3203 [HNOI2010]弹飞绵羊
P3203 [HNOI2010]弹飞绵羊
题目描述
某天,
L
o
s
t
m
o
n
k
e
y
Lostmonkey
Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,
L
o
s
t
m
o
n
k
e
y
Lostmonkey
Lostmonkey在地上沿着一条直线摆上
n
n
n个装置,每个装置设定初始弹力系数
k
i
k_i
ki,当绵羊达到第
i
i
i个装置时,它会往后弹
k
i
k_i
ki步,达到第
i
+
k
i
i+k_i
i+ki个装置,若不存在第
i
+
k
i
i+k_i
i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,
L
o
s
t
m
o
n
k
e
y
Lostmonkey
Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
输入格式
第一行包含一个整数
n
n
n,表示地上有
n
n
n个装置,装置的编号从
0
到
n
−
1
0到n-1
0到n−1。
接下来一行有
n
n
n个正整数,依次为那
n
n
n个装置的初始弹力系数。
第三行有一个正整数
m
m
m,接下来
m
m
m行每行至少有两个数
i
,
j
i,j
i,j,若
i
=
1
i=1
i=1,你要输出从
j
j
j出发被弹几次后被弹飞,若
i
=
2
i=2
i=2则还会再输入一个正整数
k
k
k,表示第
j
j
j个弹力装置的系数被修改成
k
k
k。
输出格式
对于每个
i
=
1
i=1
i=1的情况,你都要输出一个需要的步数,占一行。
输入输出样例
输入
4
1 2 1 1
3
1 1
2 1 1
1 1
输出
2
3
说明/提示
对于20%的数据
n
,
m
<
=
10000
n,m<=10000
n,m<=10000,对于100%的数据
n
<
=
200000
,
m
<
=
100000
n<=200000,m<=100000
n<=200000,m<=100000。
拿到题一脸懵逼
思路:
对于每一个块中的每一个点,维护它到下一个块中所需的次数,所到达的点,这样每一个询问只需要跳
n
\sqrt n
n次。
(倒着处理贼方便)
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline char ch(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=ch();!isdigit(x);x=ch()) if(x=='-') f=-1;
for( ;isdigit(x);x=ch()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
//编号1-n
const int A=4e5+5;
int n,m,blo;
int val[A];
int be[A];
int s[A],to[A];
inline void prepare(){
for(int i=n;i>0;i--){
if(be[i]==be[i+val[i]])
to[i]=to[i+val[i]],s[i]=s[i+val[i]]+1;
else
to[i]=i+val[i],s[i]=1;
}
return;
}
inline void change(int w,int v){
val[w]=v;
for(int i=be[w]*blo;i>(be[w]-1)*blo;i--){
if(be[i]==be[i+val[i]])
to[i]=to[i+val[i]],s[i]=s[i+val[i]]+1;
else
to[i]=i+val[i],s[i]=1;
}
return;
}
inline int qurey(int w){
int ans=0,now=w;
while(be[now]){
ans+=s[now];
now=to[now];
}
return ans;
}
signed main(){
n=in;blo=sqrt(n);
for(int i=1;i<=n;i++) val[i]=in;
for(int i=1;i<=n;i++) be[i]=(i-1)/blo+1;
prepare();
m=in;
for(int i=1;i<=m;i++){
int opt=in,u=in,v;
if(opt==1)
printf("%d\n",qurey(++u));
if(opt==2){
v=in;u++;
change(u,v);
}
}
return 0;
}