代码解析
1.pushdown,pushup模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=100000+10;
ll n,input[maxn];
struct node
{
ll val,lazy,l,r,len;//lazy用来存储需要向下传的数值信息,等询问时再一起传递
}tree[4*maxn];
void build(ll root,ll l,ll r)
{
ll m;
tree[root].lazy=0;
tree[root].l=l;
tree[root].r=r;
tree[root].len=r-l+1;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;//二分建树
build(root*2,l,m);//左子树
build(root*2+1,m+1,r);//右子树
tree[root].val=tree[root*2].val+tree[root*2+1].val;//pushup
}
}
void pushdown(ll root)
{
if(tree[root].lazy)
{
tree[root*2].lazy+=tree[root].lazy;//lazy标记传递
tree[root*2+1].lazy+=tree[root].lazy;//lazy标记传递
tree[root*2].val+=tree[root*2].len*tree[root].lazy;//lazy值传递该点的值
tree[root*2+1].val+=tree[root*2+1].len*tree[root].lazy;//lazy值传递该点的值
tree[root].lazy=0;//lazy标记清零
}
}
void update(ll root,ll l,ll r,ll x)
{
if(tree[root].l>=l&&tree[root].r<=r)//更新区间完全覆盖该子树区间
{
tree[root].lazy+=x;//更新lazy标记
tree[root].val+=tree[root].len*x;//更新该点的值
return;
}
if(tree[root].l>r||tree[root].r<l)
return;
pushdown(root);//若部分重叠,将lazy值传递下去,直到找到完全覆盖
update(root*2,l,r,x);//更新左子树
update(root*2+1,l,r,x);//更新右子树
tree[root].val=(tree[root*2].val+tree[root*2+1].val);//pushup
}
ll query(ll root,ll l,ll r)
{
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
if(tree[root].l>r||tree[root].r<l)
return 0;
pushdown(root);
return query(root*2,l,r)+query(root*2+1,l,r);
}
int main()
{
while(~scanf("%lld",&n))
{
build(1,1,n);//建树
}
return 0;
}
2.标记永久化模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=50000+10;
ll n,input[maxn];
struct node
{
ll val,lazy,l,r,len;
}tree[4*maxn];
void build(ll root,ll l,ll r)//build部分不变
{
ll m;
tree[root].lazy=0;
tree[root].l=l;
tree[root].r=r;
tree[root].len=r-l+1;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;
build(root*2,l,m);
build(root*2+1,m+1,r);
tree[root].val=tree[root*2].val+tree[root*2+1].val;
}
}
void update(ll root,ll l,ll r,ll x)//更新每一个点!
{
tree[root].val+=(r-l+1)*x;
if(tree[root].l==l&&tree[root].r==r)//必须完全重合才可加lazy
{
tree[root].lazy+=x;
return;
}
ll mid=(tree[root].l+tree[root].r)/2;//下标为root的结点的l与r的中点
if(r<=mid)//如果更新区间的右边界比这个mid小,那么找这个root的左儿子,缩小区间
update(root*2,l,r,x);
else if(l>mid)//如果更新区间的左边界比这个mid大,那么找这个root的右儿子,缩小区间
update(root*2+1,l,r,x);
else
{
update(root*2,l,mid,x);
update(root*2+1,mid+1,r,x);
}
}
ll query(ll root,ll l,ll r,ll ad)//询问时累加标记,标记初始为0
{
if(tree[root].l==l&&tree[root].r==r)
return tree[root].val+tree[root].len*ad;
ll mid=(tree[root].l+tree[root].r)/2;
if(r<=mid) return query(root*2,l,r,ad+tree[root].lazy);
if(l>mid) return query(root*2+1,l,r,ad+tree[root].lazy);
return query(root*2,l,mid,ad+tree[root].lazy)+query(root*2+1,mid+1,r,ad+tree[root].lazy);
}
int main()
{
while(~scanf("%lld",&n))
{
build(1,1,n);
}
return 0;
}
主要思想:分治
递归解决问题
优化方案:lazy标记
优化方案2:标记永久化
经典例题
1001-敌兵布阵
题目来源:hdoj(1166)
1.lazytag解法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<long long,long long> pll;
const int inf = 0x3f3f3f3f;
const int maxn=100000+10;
ll n,input[maxn];
struct node
{
ll val,lazy,l,r,len;//lazy用来存储需要向下传的数值信息,等询问时再一起传递
}tree[4*maxn];
void build(ll root,ll l,ll r)
{
ll m;
tree[root].lazy=0;
tree[root].l=l;
tree[root].r=r;
tree[root].len=r-l+1;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;//二分建树
build(root*2,l,m);//左子树
build(root*2+1,m+1,r);//右子树
tree[root].val=tree[root*2].val+tree[root*2+1].val;//pushup
}
}
void pushdown(ll root)
{
if(tree[root].lazy)
{
tree[root*2].lazy+=tree[root].lazy;//lazy标记传递
tree[root*2+1].lazy+=tree[root].lazy;//lazy标记传递
tree[root*2].val+=tree[root*2].len*tree[root].lazy;//lazy值传递该点的值
tree[root*2+1].val+=tree[root*2+1].len*tree[root].lazy;//lazy值传递该点的值
tree[root].lazy=0;//lazy标记清零
}
}
void update(ll root,ll l,ll r,ll x)
{
if(tree[root].l>=l&&tree[root].r<=r)//更新区间完全覆盖该子树区间
{
tree[root].lazy+=x;//更新lazy标记
tree[root].val+=tree[root].len*x;//更新该点的值
return;
}
if(tree[root].l>r||tree[root].r<l)
return;
pushdown(root);//若部分重叠,将lazy值传递下去,直到找到完全覆盖
update(root*2,l,r,x);//更新左子树
update(root*2+1,l,r,x);//更新右子树
tree[root].val=(tree[root*2].val+tree[root*2+1].val);//pushup
}
ll query(ll root,ll l,ll r)
{
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
if(tree[root].l>r||tree[root].r<l)
return 0;
pushdown(root);
return query(root*2,l,r)+query(root*2+1,l,r);
}
void solve()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
scanf("%lld",&input[i]);
build(1,1,n);//建树
string s;
ll a,b;
while(cin>>s)
{
if(s=="End")
break;
cin>>a>>b;
if(s=="Query")
printf("%lld\n",query(1,a,b));
else if(s=="Sub")
update(1,a,a,-b);
else if(s=="Add")
update(1,a,a,b);
}
return;
}
int main()
{
ll T;
scanf("%lld",&T);
for(ll t0=1;t0<=T;t0++)
{
printf("Case %lld:\n",t0);
solve();
}
return 0;
}
2.标记永久化解法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=50000+10;
ll n,input[maxn];
struct node
{
ll val,lazy,l,r,len;
}tree[4*maxn];
void build(ll root,ll l,ll r)
{
ll m;
tree[root].lazy=0;
tree[root].l=l;
tree[root].r=r;
tree[root].len=r-l+1;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;
build(root*2,l,m);
build(root*2+1,m+1,r);
tree[root].val=tree[root*2].val+tree[root*2+1].val;
}
}
void update(ll root,ll l,ll r,ll addval)
{
tree[root].val+=(r-l+1)*addval;
if(tree[root].l==l&&tree[root].r==r)
{
tree[root].lazy+=addval;
return;
}
ll mid=(tree[root].l+tree[root].r)/2;
if(r<=mid)
update(root*2,l,r,addval);
else if(l>mid)
update(root*2+1,l,r,addval);
else
{
update(root*2,l,mid,addval);
update(root*2+1,mid+1,r,addval);
}
}
ll query(ll root,ll l,ll r,ll ad)
{
if(tree[root].l==l&&tree[root].r==r)
return tree[root].val+tree[root].len*ad;
ll mid=(tree[root].l+tree[root].r)/2;
if(r<=mid) return query(root*2,l,r,ad+tree[root].lazy);
if(l>mid) return query(root*2+1,l,r,ad+tree[root].lazy);
return query(root*2,l,mid,ad+tree[root].lazy)+query(root*2+1,mid+1,r,ad+tree[root].lazy);
}
void solve()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
scanf("%lld",&input[i]);
build(1,1,n);//建树
string s;
ll a,b;
while(cin>>s)
{
if(s=="End")
break;
cin>>a>>b;
if(s=="Query")
printf("%lld\n",query(1,a,b,0));
else if(s=="Sub")
update(1,a,a,-b);
else if(s=="Add")
update(1,a,a,b);
}
return;
}
int main()
{
ll T;
scanf("%lld",&T);
for(ll t0=1;t0<=T;t0++)
{
printf("Case %lld:\n",t0);
solve();
}
return 0;
}
易错点:全部用cin读入会超时!!!还是尽量多用scanf为好
1002-I Hate It
题目来源:hdoj1754
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=200000+10;
ll n,m,input[maxn];
struct node
{
ll val,l,r;
}tree[4*maxn];
void build(ll root,ll l,ll r)//build部分不变
{
ll m;
tree[root].l=l;
tree[root].r=r;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;
build(root*2,l,m);
build(root*2+1,m+1,r);
tree[root].val=max(tree[root*2].val,tree[root*2+1].val);
}
}
void update(ll root,ll l,ll r,ll x)
{
if(tree[root].l>=l&&tree[root].r<=r)
{
tree[root].val=x;
return;
}
if(tree[root].l>r||tree[root].r<l)
return;
update(root*2,l,r,x);
update(root*2+1,l,r,x);
tree[root].val=max(tree[root*2].val,tree[root*2+1].val);
}
ll query(ll root,ll l,ll r)
{
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
if(tree[root].l>r||tree[root].r<l)
return 0;
return max(query(root*2,l,r),query(root*2+1,l,r));
}
void solve()
{
build(1,1,n);
while(m--)
{
char c;
ll a,b;
cin>>c>>a>>b;
if(c=='Q')
printf("%lld\n",query(1,a,b));
else
update(1,a,a,b);
}
return;
}
int main()
{
while(~scanf("%lld%lld",&n,&m))
{
for(ll i=1;i<=n;i++)
scanf("%lld",&input[i]);
solve();
}
return 0;
}
1003-A Simple Problem with Integers
题目来源:hdoj4267
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=50000+1;
int n,input[maxn];
struct node
{
int val,l,r;
int sum[57];
}tree[4*maxn];
void build(int root,int l,int r)//build部分不变
{
int m;
memset(tree[root].sum,0,sizeof(tree[root].sum));
tree[root].l=l;
tree[root].r=r;
if(l==r)
tree[root].val=input[l];
else
{
m=(l+r)/2;
build(root*2,l,m);
build(root*2+1,m+1,r);
}
}
void update(int root,int l,int r,int k,int x)
{
if(tree[root].l>=l&&tree[root].r<=r)
{
tree[root].sum[k*(k-1)/2+(tree[root].l-l)%k]+=x;
return;
}
if(tree[root].l>r||tree[root].r<l)
return;
update(root*2,l,r,k,x);
update(root*2+1,l,r,k,x);
}
int query(int root,int x)
{
if(tree[root].l>x||tree[root].r<x)
return 0;
int ans=0;
for(int i=1;i<=10;i++)
for(int j=0;j<i;j++)
if((x-tree[root].l+j)%i==0)
ans+=tree[root].sum[i*(i-1)/2+j];
if(tree[root].l==tree[root].r)
return ans+=tree[root].val;
int m=(tree[root].l+tree[root].r)/2;
return ans+=query(root*2,x)+query(root*2+1,x);
}
void solve()
{
build(1,1,n);
int m,op,a,b,c,d;
scanf("%d",&m);
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
update(1,a,b,c,d);
}
else
{
scanf("%d",&a);
printf("%d\n",query(1,a));
}
}
return;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
scanf("%d",&input[i]);
solve();
}
return 0;
}
这题让我推开了新世界的大门
首先先说一下坑点,如果你是一位longlongint选手,那么恭喜你,你很有可能会像我一样,memory limited exceeded。请不要没事define int long long int
对这个sum做一点解释:
k*(k-1)/2就是0到k-1的和
比方说k=1的时候,这个和就是0,余数必然为0,存储一种情况(sum[0])
k=2的时候,这个和就是1,此时余数可以为0或为1,存储两种情况(sum[1+0],sum[1+1])
k=3的时候,这个和就是3,此时余数可以为0或为1或为2,存储两种情况(sum[3+0],sum[3+1],sum[3+2])
1004-Just a Hook
题目来源:hdoj1698
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<long long,long long> pll;
const int inf = 0x3f3f3f3f;
const int maxn=100000+10;
ll n,input[maxn];
struct node
{
ll val,lazy,l,r,len;
}tree[4*maxn];
void build(ll root,ll l,ll r)
{
ll m;
tree[root].lazy=0;
tree[root].l=l;
tree[root].r=r;
tree[root].len=r-l+1;
if(l==r)
tree[root].val=1;
else
{
m=(l+r)/2;
build(root*2,l,m);
build(root*2+1,m+1,r);
tree[root].val=tree[root*2].val+tree[root*2+1].val;
}
}
void pushdown(ll root)
{
if(tree[root].lazy)
{
tree[root*2].lazy=tree[root].lazy;
tree[root*2+1].lazy=tree[root].lazy;
tree[root*2].val=tree[root*2].len*tree[root].lazy;
tree[root*2+1].val=tree[root*2+1].len*tree[root].lazy;
tree[root].lazy=0;
}
}
void update(ll root,ll l,ll r,ll x)
{
if(tree[root].l>=l&&tree[root].r<=r)
{
tree[root].lazy=x;
tree[root].val=tree[root].len*x;
return;
}
if(tree[root].l>r||tree[root].r<l)
return;
pushdown(root);
update(root*2,l,r,x);
update(root*2+1,l,r,x);
tree[root].val=(tree[root*2].val+tree[root*2+1].val);
}
ll query(ll root,ll l,ll r)
{
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
if(tree[root].l>r||tree[root].r<l)
return 0;
pushdown(root);
return query(root*2,l,r)+query(root*2+1,l,r);
}
void solve()
{
ll m;
ll a,b,c;
scanf("%lld%lld",&n,&m);
build(1,1,n);
while(m--)
{
scanf("%lld%lld%lld",&a,&b,&c);
update(1,a,b,c);
}
printf("%lld.\n",query(1,1,n));
return;
}
int main()
{
ll T;
scanf("%lld",&T);
for(ll i=1;i<=T;i++)
{
printf("Case %lld: The total value of the hook is ",i);
solve();
}
return 0;
}
模板题
1005-LCIS
题目来源:hdoj3308
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10000;
int n,m,a,b,t,ans;
int x[maxn];
char op[2];
struct node{
int l,r; //左右边界
int ls,rs; //左右边界的值
int lsum,rsum,sum; //左右最大LCIS 区间最大LCIS
}tree[maxn*4];
void pushup(int rt)
{
tree[rt].ls=tree[rt*2].ls;
tree[rt].rs=tree[rt*2+1].rs;
tree[rt].lsum=tree[rt*2].lsum;
tree[rt].rsum=tree[rt*2+1].rsum;
tree[rt].sum=max(tree[rt*2].sum,tree[rt*2+1].sum);
if(tree[rt*2].rs<tree[rt*2+1].ls)
{//如果左子树的右边界值小于右子树的左边界值 合并左子树的右边界和右子树的左边界进行计算
if(tree[rt*2].lsum==(tree[rt*2].r-tree[rt*2].l+1))
tree[rt].lsum+=tree[rt*2+1].lsum;
if(tree[rt*2+1].rsum==(tree[rt*2+1].r-tree[rt*2+1].l+1))
tree[rt].rsum+=tree[rt*2].rsum;
tree[rt].sum=max(tree[rt].sum,tree[rt*2].rsum+tree[rt*2+1].lsum);
}
}
void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].lsum=tree[rt].rsum=tree[rt].sum=1;
tree[rt].ls=tree[rt].rs=x[l];
return;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
pushup(rt);
}
void update(int rt)
{
if(tree[rt].l==tree[rt].r)
{
tree[rt].ls=tree[rt].rs=b;
return;
}
int mid=(tree[rt].l+tree[rt].r)/2;
if(a<=mid) update(rt*2);
else update(rt*2+1);
pushup(rt);
}
int query(int rt)
{
if(tree[rt].l>=a && tree[rt].r<=b)
return tree[rt].sum;
int mid=(tree[rt].l+tree[rt].r)/2;
int ans=0;
if(a<=mid) ans=max(ans,query(rt*2));
if(b>mid) ans=max(ans,query(rt*2+1));
if(tree[rt*2].rs<tree[rt*2+1].ls)
ans=max(ans,min(mid-a+1,tree[rt*2].rsum)+min(b-mid,tree[rt*2+1].lsum));
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&x[i]);
build(1,n,1);
for(int i=1;i<=m;i++)
{
scanf("%s%d%d",op,&a,&b);
if(op[0]=='U')
{
a++;
update(1);
}
if(op[0]=='Q')
{
a++;b++;
printf("%d\n",query(1));
}
}
}
return 0;
}