首先是纯纯坐牢(没doge)
题目地址:
目录
DAY 7.11
目前有点感觉的是:
二维树状数组的(区查单改,单查区改),线段树模板,稍微复杂一点的线段树模板,理解pushdown,pushup,分块和莫队的思路和时间复杂度(对勾函数的感觉),维护前缀和的线段树,权值线段树的一点点。。
下面是板子:
板子改进了一下,对称美观,增加了可读性
二维树状数组(单点修改,区间查询)
int a[M][M];
int n,m;
int lowbit(int x){
return x&(-x);
}
void add(int x,int y,int w){
while (x<=n){
int i=y;
while (i<=m){
a[x][i]+=w;
i+=lowbit(i);
}
x+=lowbit(x);
}
}
int sum(int x,int y){
int ans=0;
while (x>0){
int i=y;
while (i>0){
ans+=a[x][i];
i-=lowbit(i);
}
x-=lowbit(x);
}
return ans;
}
int query(int x1,int y1,int x2,int y2){
return sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1);
}
void work(){
cin>>n>>m;
int op,x,y,k,a,b,c,d;
while (cin>>op){
if (op==1){
cin>>x>>y>>k;
add(x,y,k);
}
else{
cin>>a>>b>>c>>d;
cout<<query(a,b,c,d)<<endl;
}
}
}
signed main(){
CIO;
work();
return 0;
}
二维树状数组(区间修改,单点查询)
int a[M][M];
int n,m;
int lowbit(int x){
return x&(-x);
}
void add(int x,int y,int w){
while (x<=n){
int i=y;
while (i<=m){
a[x][i]+=w;
i+=lowbit(i);
}
x+=lowbit(x);
}
}
int sum(int x,int y){
int ans=0;
while (x>0){
int i=y;
while (i>0){
ans+=a[x][i];
i-=lowbit(i);
}
x-=lowbit(x);
}
return ans;
}
int query(int x1,int y1){
return sum(x1,y1);
}
void work(){
cin>>n>>m;
int op,x,y,k,a,b,c,d;
while (cin>>op){
if (op==1){
cin>>a>>b>>c>>d>>k;
add(a,b,k);
add(a,d+1,-k);
add(c+1,b,-k);
add(c+1,d+1,k);
}
else{
cin>>x>>y;
cout<<query(x,y)<<endl;
}
}
}
signed main(){
CIO;
work();
return 0;
}
二维树状数组(区间修改,区间查询)
暂无
线段树
int tr[4*N],num[N],laz[4*N];
void build(int p,int l,int r){
if (l==r){
tr[p]=num[l];
return;
}
int mid=l+r>>1;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
tr[p]=tr[2*p]+tr[2*p+1];
}
//build(1,1,n);
void pushdown(int p,int l,int r){
int mid=l+r>>1;
laz[2*p]+=laz[p];
laz[2*p+1]+=laz[p];
tr[2*p]+=laz[p]*(mid-l+1);
tr[2*p+1]+=laz[p]*(r-mid);
laz[p]=0;
}
int query(int p,int l,int r,int x,int y){
if (x<=l&&r<=y){
return tr[p];
}
pushdown(p,l,r);
int mid=l+r>>1,ans=0;
if (x<=mid)ans+=query(2*p,l,mid,x,y);
if (mid<y)ans+=query(2*p+1,mid+1,r,x,y);
return ans;
}
void update(int p,int l,int r,int x,int y,int w){
if (x<=l&&r<=y){
tr[p]+=w*(r-l+1);
laz[p]+=w;
return ;
}
pushdown(p,l,r);
int mid=l+r>>1;
if (x<=mid)update(2*p,l,mid,x,y,w);
if (mid<y)update(2*p+1,mid+1,r,x,y,w);
tr[p]=tr[2*p]+tr[2*p+1];
}
例题:P3373 【模板】线段树 2
树用结构体装起来,pushdown是关键,这种维护得仔细考虑各个方面。
#include <bits/stdc++.h>
#define int long long
#define CIO std::ios::sync_with_stdio(false)
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define nep(i, r, l) for (int i = r; i >= l; i--)
#define pii pair<int,int>
using namespace std;
const int N=2e5+5;
struct node{
int sum,mu,add,l,r;
}tr[4*N];
int num[N],laz[4*N];
int n,m,mod;
void build(int p,int l,int r){
tr[p].l=l;tr[p].r=r;tr[p].mu=1;
if (l==r){
tr[p].sum=num[l]%mod;
return;
}
int mid=(l+r)>>1;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
tr[p].sum=(tr[2*p].sum+tr[2*p+1].sum)%mod;
}
void pushdown(int p){
tr[2*p].sum=(tr[p].mu*tr[2*p].sum%mod+(tr[p].add*(tr[2*p].r-tr[2*p].l+1)%mod)%mod)%mod;
tr[2*p+1].sum=(tr[p].mu*tr[2*p+1].sum%mod+(tr[p].add*(tr[2*p+1].r-tr[2*p+1].l+1)%mod)%mod)%mod;
tr[2*p].mu=(tr[2*p].mu*tr[p].mu)%mod;
tr[2*p+1].mu=(tr[2*p+1].mu*tr[p].mu)%mod;
tr[2*p].add=(tr[2*p].add*tr[p].mu+tr[p].add)%mod;
tr[2*p+1].add=(tr[2*p+1].add*tr[p].mu+tr[p].add)%mod;
tr[p].mu=1;tr[p].add=0;
}
void add(int p,int x,int y,int w){
if (x<=tr[p].l&&tr[p].r<=y){
tr[p].add=(tr[p].add+w)%mod;
tr[p].sum=(tr[p].sum+w*(tr[p].r-tr[p].l+1))%mod;
return;
}
pushdown(p);
tr[p].sum=(tr[2*p].sum+tr[2*p+1].sum)%mod;
int mid=(tr[p].l+tr[p].r)>>1;
if (x<=mid) add(2*p,x,y,w);
if (mid<y) add(2*p+1,x,y,w);
tr[p].sum=(tr[2*p].sum+tr[2*p+1].sum)%mod;
}
void mu(int p,int x,int y,int k){
if (x<=tr[p].l&&tr[p].r<=y){
tr[p].sum=(tr[p].sum*k)%mod;
tr[p].add=(tr[p].add*k)%mod;
tr[p].mu=(tr[p].mu*k)%mod;
return;
}
pushdown(p);
tr[p].sum=(tr[2*p].sum+tr[2*p+1].sum)%mod;
int mid=(tr[p].l+tr[p].r)>>1;
if (x<=mid) mu(2*p,x,y,k);
if (mid<y) mu(2*p+1,x,y,k);
tr[p].sum=(tr[2*p].sum+tr[2*p+1].sum)%mod;
}
int query(int p,int x,int y){
if (x<=tr[p].l&&tr[p].r<=y){
return tr[p].sum;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)>>1,ans=0;
if (x<=mid)ans+=query(2*p,x,y)%mod;
ans=ans%mod;
if (mid<y)ans+=query(2*p+1,x,y)%mod;
ans=ans%mod;
return ans;
}
void work(){
cin>>n>>m>>mod;
int op;
rep(i,1,n)
cin>>num[i];
int a,b,w;
build(1,1,n);
rep(i,1,m){
cin>>op;
if (op==1){
cin>>a>>b>>w;
mu(1,a,b,w);
}
else if (op==2){
cin>>a>>b>>w;
add(1,a,b,w);
}
else{
cin>>a>>b;
cout<<query(1,a,b)<<endl;
}
}
}
signed main(){
CIO;
work();
return 0;
}
例题:P1908 逆序对
一道思维题,可以转化成树状数组做
#include <bits/stdc++.h>
#define int long long
#define CIO std::ios::sync_with_stdio(false)
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define nep(i, r, l) for (int i = r; i >= l; i--)
#define pii pair<int,int>
using namespace std;
const int N=5e5+5;
int d[N],rnk[N];
struct shu{
int idx;
int val;
}a[N];
int n;
bool cmp(shu p,shu q){
if (p.val==q.val){
return p.idx<q.idx;
}
return p.val<q.val;
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int w){
while (x<=n){
d[x]+=w;
x+=lowbit(x);
}
}
int query(int x){
int ans=0;
while (x>0){
ans+=d[x];
x-=lowbit(x);
}
return ans;
}
void work(){
cin>>n;
rep(i,1,n){
cin>>a[i].val;
a[i].idx=i;
}
sort(a+1,a+n+1,cmp);
int sum=0;
rep(i,1,n){
rnk[a[i].idx]=i;
}
rep(i,1,n){
add(rnk[i],1);
sum+=i-query(rnk[i]);
}
cout<<sum<<endl;
}
signed main(){
CIO;
work();
return 0;
}
例题:P4513 小白逛公园
利用前缀最大和,后缀最大和,和 来递归求出最大子段和。
主要利用的是pushup
#include <bits/stdc++.h>
#define int long long
#define CIO std::ios::sync_with_stdio(false)
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define nep(i, r, l) for (int i = r; i >= l; i--)
#define pii pair<int,int>
using namespace std;
const int N=5e5+5;
struct tree{
int l,r,mxl,mxr,sum,ans;
}t[4*N];
int n,m;
int a[N];
int pushup(int p){
t[p].sum=t[2*p].sum+t[2*p+1].sum;
t[p].mxl=max(t[2*p].mxl,t[2*p].sum+t[2*p+1].mxl);
t[p].mxr=max(t[2*p+1].mxr,t[2*p+1].sum+t[2*p].mxr);
t[p].ans=max(max(t[2*p].ans,t[2*p+1].ans),t[2*p].mxr+t[2*p+1].mxl);
}
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
if (l==r){
t[p].sum=a[l];
t[p].mxl=t[p].mxr=t[p].ans=a[l];
return;
}
int mid=(l+r)>>1;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
pushup(p);
}
tree query(int p,int x,int y){
if (x<=t[p].l&&t[p].r<=y){
return t[p];
}
int mid=(t[p].l+t[p].r)>>1;
if (y<=mid) return query(2*p,x,y);
else if (x>mid) return query(2*p+1,x,y);
else{
tree T,a,b;
a=query(2*p,x,y);
b=query(2*p+1,x,y);
T.mxl=max(a.mxl,a.sum+b.mxl);
T.mxr=max(b.mxr,b.sum+a.mxr);
T.ans=max(max(a.ans,b.ans),a.mxr+b.mxl);
return T;
}
}
void change(int p,int x,int w){
if (t[p].l==t[p].r){
t[p].mxl=t[p].mxr=t[p].ans=t[p].sum=w;
return;
}
int mid=(t[p].l+t[p].r)>>1;
if (x<=mid) change(2*p,x,w);
else change(2*p+1,x,w);
pushup(p);
}
void work(){
int n,m;
cin>>n>>m;
rep(i,1,n){
cin>>a[i];
}
build(1,1,n);
rep(i,1,m){
int op,x,y;
cin>>op;
if (op==1){
cin>>x>>y;
if (y<x) swap(x,y);
cout<<query(1,x,y).ans<<endl;
}
else{
cin>>x>>y;
change(1,x,y);
}
}
}
signed main(){
CIO;
work();
return 0;
}
未完待补