模板系列---数据结构
P3378 【模板】堆
题目简述
给定三个操作,求数列中最小的数,删除数列中最小的数,插入一个新的数
思路
板子题没什么好说,用 stl 自带的优先队列很好写,但手写的也要掌握。
建议参考这篇博客
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6;
int tr[N];
int main(){
int n,len=0;
cin>>n;
while(n--){
int op;
cin>>op;
switch(op){
case 1:{
int x;
cin>>x;
tr[++len]=x;
int kdl=len;
while(kdl){
if(tr[kdl>>1]>tr[kdl])tr[kdl>>1]^=tr[kdl]^=tr[kdl>>1]^=tr[kdl];
else break;
kdl>>=1;
}
break;
}
case 2:{
cout<<tr[1]<<endl;
break;
}
case 3:{
int kdl=1;
tr[len]^=tr[1]^=tr[len]^=tr[1];
tr[len]=0;
len--;
while(kdl<len){
int ls=(kdl<<1),rs=(kdl<<1|1);
if(ls>len){
break;
}
if(rs>len){
if(tr[ls]<tr[kdl])tr[kdl]^=tr[ls]^=tr[kdl]^=tr[ls];
break;
}
if(tr[ls]<tr[rs]){
if(tr[ls]<tr[kdl])tr[kdl]^=tr[ls]^=tr[kdl]^=tr[ls],kdl=ls;
else break;
}
else {
if(tr[rs]<tr[kdl])tr[kdl]^=tr[rs]^=tr[kdl]^=tr[rs],kdl=rs;
else break;
}
}
break;
}
}
}
return 0;
}
PS:有时候真的很奇怪我是怎么能把代码都写这么冗长的/kk
P3865 【模板】ST 表
题目简述
对于给定的数列,要求以\(\theta(1)\)的时间复杂度计算出\([l_i,r_i]\)中最大值
思路
没什么可讲的,但要注意,计算区间长度的对数要是 log2(r-l+1) 不加1的话大多数情况下没问题,但是当 l=r 的时候会报错
BTW,用scanf printf 不会超时,用cin cout 是会超时的qwq
具体思路可以参考这个博客
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],s[N][25];
int n,m;
void in(int &x){
x=0;
int f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
x*=f;
}
void pre_work(){
for(int i=1;(1<<i)<=n&&i<25;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
s[j][i]=max(s[j][i-1],s[j+(1<<(i-1))][i-1]);
}
}
}
void query(int l,int r){
int k=log2(r-l+1);
printf("%d\n",max(s[l][k],s[r-(1<<k)+1][k]));
}
int main(){
in(n);in(m);
for(int i=1;i<=n;i++)in(s[i][0]);
pre_work();
for(int i=1;i<=m;i++){
int l,r;
in(l);in(r);
query(l,r);
}
return 0;
}
P3372 【模板】线段树 1
题目简述
对于一段数列,有如下两种操作
1 x y k:将区间 \([x, y]\) 内每个数加上 \(k\)。2 x y:输出区间 \([x, y]\) 内每个数的和。
思路
线段树裸树
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5;
ll a[N],n,m;
ll tr[N],tag[N];
void in(ll &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
x*=f;
}
ll ls(ll root){
return root<<1;
}
ll rs(ll root){
return root<<1|1;
}
void push_up(ll root){
tr[root]=tr[ls(root)]+tr[rs(root)];
}
void work(ll l,ll r,ll root,ll k){
tag[root]+=k;
tr[root]+=(r-l+1)*k;
}
void push_down(ll l,ll r,ll root){
ll mid=(l+r)>>1;
work(l,mid,ls(root),tag[root]);
work(mid+1,r,rs(root),tag[root]);
tag[root]=0;
}
void build(ll root,ll l,ll r){
ll mid=(l+r)>>1;
if(l==r){
tr[root]=a[l];
return ;
}
build(ls(root),l,mid);
build(rs(root),mid+1,r);
push_up(root);
return ;
}
void update(ll nl,ll nr,ll l,ll r,ll root,ll num){
if(l>=nl&&r<=nr){
tr[root]+=(r-l+1)*num;
tag[root]+=num;
return ;
}
//cout<<l<<' '<<r<<endl;
push_down(l,r,root);
ll mid=(l+r)>>1;
if(mid>=nl)update(nl,nr,l,mid,ls(root),num);
if(mid<nr)update(nl,nr,mid+1,r,rs(root),num);
push_up(root);
return ;
}
ll query(ll nl,ll nr,ll l,ll r,ll root){
ll ans=0;
if(l>=nl&&r<=nr)return tr[root];
ll mid=(l+r)>>1;
push_down(l,r,root);
if(mid>=nl)ans+=query(nl,nr,l,mid,ls(root));
if(mid<nr)ans+=query(nl,nr,mid+1,r,rs(root));
return ans;
}
int main(){
freopen("3372.in","r",stdin);
freopen("3372.out","w",stdout);
in(n);in(m);
for(int i=1;i<=n;i++)in(a[i]);
build (1,1,n);
for(int i=1;i<=m;i++){
ll op;
in(op);
switch(op){
case 1:{
ll x,y,k;
in(x);in(y);in(k);
update(x,y,1,n,1,k);
break;
}
case 2:{
ll x,y;
in(x);in(y);
cout<<query(x,y,1,n,1)<<endl;
break;
}
}
}
return 0;
}
P3373 【模板】线段树 2
题目简述
对于一段数列,有如下两种操作
1 x y k:将区间 \([x, y]\) 内每个数乘上 \(k\)。2 x y k:输出区间 \([x, y]\) 内每个数加上 \(k\)。3 x y:输出区间 \([x, y]\) 内每个数的和。
思路
线段树裸树
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e5+5;
ll a[N],tag_add[N],tag_mul[N],tr[N];
ll n,m,p;
inline ll ls(ll root){
return root<<1;
}
inline ll rs(ll root){
return root<<1|1;
}
void push_up(ll root){
tr[root]=tr[ls(root)]+tr[rs(root)];
}
void build(ll root,ll l,ll r){
tag_add[root]=0;
tag_mul[root]=1;
ll mid=(l+r)>>1;
if(l==r){
tr[root]=a[l];
tr[root]%=p;
return ;
}
build(ls(root),l,mid);
build(rs(root),mid+1,r);
push_up(root);
return ;
}
void push_down(ll root,ll l,ll r){
ll mid=(l+r)>>1;
tr[ls(root)]=(tr[ls(root)]*tag_mul[root]+tag_add[root]*(mid-l+1))%p;
tr[rs(root)]=(tr[rs(root)]*tag_mul[root]+tag_add[root]*(r-mid))%p;
tag_mul[ls(root)]*=tag_mul[root];
tag_mul[ls(root)]%=p;
tag_mul[rs(root)]*=tag_mul[root];
tag_mul[rs(root)]%=p;
tag_add[ls(root)]=tag_add[ls(root)]*tag_mul[root]+tag_add[root];
tag_add[ls(root)]%=p;
tag_add[rs(root)]=tag_add[rs(root)]*tag_mul[root]+tag_add[root];
tag_add[rs(root)]%=p;
tag_add[root]=0;
tag_mul[root]=1;
}
void mul(ll nl,ll nr,ll root,ll l,ll r,ll num){
if(l>=nl&&r<=nr){
tr[root]=(tr[root]*num)%p;
tag_add[root]=(tag_add[root]*num)%p;
tag_mul[root]=(tag_mul[root]*num)%p;
return ;
}
push_down(root,l,r);
ll mid=(l+r)>>1;
if(mid>=nl) mul(nl,nr,ls(root),l,mid,num);
if(mid+1<=nr) mul(nl,nr,rs(root),mid+1,r,num);
push_up(root);
return ;
}
void add(ll nl,ll nr,ll root,ll l,ll r,ll num){
if(l>=nl&&r<=nr){
tr[root]=(tr[root]+num*(r-l+1))%p;
tag_add[root]=(tag_add[root]+num)%p;
return ;
}
push_down(root,l,r);
ll mid=(l+r)>>1;
if(mid>=nl) add(nl,nr,ls(root),l,mid,num);
if(mid+1<=nr) add(nl,nr,rs(root),mid+1,r,num);
push_up(root);
return ;
}
ll query(ll nl,ll nr,ll root,ll l,ll r){
if(l>=nl&&r<=nr){
return tr[root];
}
ll ans=0;
push_down(root,l,r);
ll mid=(l+r)>>1;
if(mid>=nl) ans=(ans+query(nl,nr,ls(root),l,mid))%p;
if(mid+1<=nr) ans=(ans+query(nl,nr,rs(root),mid+1,r))%p;
return ans;
}
int main(){
cin>>n>>m>>p;
for(ll i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
//cout<<tr[1]<<endl;
for(ll i=1;i<=m;i++){
ll op;
cin>>op;
switch(op){
case 1:{
ll x,y,k;
cin>>x>>y>>k;
mul(x,y,1,1,n,k);
break;
}
case 2:{
ll x,y,k;
cin>>x>>y>>k;
add(x,y,1,1,n,k);
break;
}
case 3:{
ll x,y;
cin>>x>>y;
cout<<query(x,y,1,1,n)<<endl;;
break;
}/**/
}
}
return 0;
}

浙公网安备 33010602011771号