势能分块模板

分块:

  • 把n分成sqrt(n)块, 中间整体修改,2边暴力修改即可, 修改,查询的复杂度为3sqr(n);
  • 比线段树好写一些?
  • 当然整体的修改的时候,有时候要用 lz 去处理, 
  • 和势能线段树有共同的思想.

模板:

建块:

cin>>n;
    int d=sqrt(n);
    int kn=0;
    for(ri i=1;i<=n;i++) p[i].l=n,p[i].r=0;
    for(ri i=1;i<=n;i++)
    {
        cin>>val[i];
        int a=i/d+1;kn=max(kn,a);
        p[a].val+=val[i];
        p[a].l=min(i,p[a].l);
        p[a].r=max(p[a].r,i);
    }
View Code

处理:

cin>>m;
    for(ri i=1;i<=m;i++)
    {
        int op,a,b;
        cin>>op>>a>>b;
        if(a>b) swap(a,b);
        if(op==0)
        {
            for(ri now=a;now<=b;now=p[now/d+1].r+1)
            {
            //    cout<<now<<"\n";
                int tmp=now/d+1;
                if(p[tmp].r<=b&&now==p[tmp].l)
                {
                    p[tmp].cnt++;    
                }
                else
                {
                    if(p[tmp].cnt) xiu(tmp);
                    if(p[tmp].flag)
                    {
                        
                        continue;
                    }
                    for(ri j=now;j<=min(p[tmp].r,b);j++)
                    {
                        p[tmp].val-=val[j];
                        val[j]=sqrt(val[j]);
                        p[tmp].val+=val[j];
                    }
                    if(p[tmp].r-p[tmp].l+1==p[tmp].val) p[tmp].flag=1;
                }
                    
            }
        }
        else
        {
            long long ans=0;
            for(ri now=a;now<=b;now=p[now/d+1].r+1)
            {
                int tmp=now/d+1;
                if(p[tmp].r<=b&&now==p[tmp].l)
                {
                    if(p[tmp].flag) ans+=p[tmp].val;
                    else 
                    {
                        if(p[tmp].cnt) xiu(tmp);
                        ans+=p[tmp].val;    
                    }    
                }
                else
                {
                    if(p[tmp].cnt) xiu(tmp);
                    if(p[tmp].flag)
                    {
                        ans+=min(p[tmp].r,b)-now+1;
                     
                        continue;
                    }
                    for(ri j=now;j<=min(p[tmp].r,b);j++)
                    {
                        ans+=val[j];
                    }
                }    
            
            }
            cout<<ans<<"\n";
        }
View Code

后记:

  • 最外层的循环: for(ri now=a;now<=b;now=p[now/d+1].r+1) 
  • 一个是整块的判断 now==l, b>=p[tmp].r
  • 一个是暴力的循环: for now to min(b,p[tmp].r)

 

例题:

 

思路:

  • 势能线段树的思想,很快就会变成1, 于是就不用处理了
#include <bits/stdc++.h>
using namespace std;
#define ri register   int 
#define M 2000005

struct dian{
    int l,r;
    long long val;
    int cnt=0;
    int flag=0;
}p[M];
long long  val[M];
int n,m;
void xiu(int a)
{
    if(p[a].flag) return ;
    p[a].val=0;
    for(ri i=p[a].l;i<=p[a].r;i++)
    {
        for(ri j=1;j<=p[a].cnt;j++)
        {
            val[i]=sqrt(val[i]);
            if(val[i]==1) break;
        }
        p[a].val+=val[i];
    }
    p[a].cnt=0;
    if(p[a].val==(p[a].r-p[a].l+1)) p[a].flag=1;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);///////////////////////////////////////////
    
    cin>>n;
    int d=sqrt(n);
    int kn=0;
    for(ri i=1;i<=n;i++) p[i].l=n,p[i].r=0;
    for(ri i=1;i<=n;i++)
    {
        cin>>val[i];
        int a=i/d+1;kn=max(kn,a);
        p[a].val+=val[i];
        p[a].l=min(i,p[a].l);
        p[a].r=max(p[a].r,i);
    }
    cin>>m;
    for(ri i=1;i<=m;i++)
    {
        int op,a,b;
        cin>>op>>a>>b;
        if(a>b) swap(a,b);
        if(op==0)
        {
            for(ri now=a;now<=b;now=p[now/d+1].r+1)
            {
            //    cout<<now<<"\n";
                int tmp=now/d+1;
                if(p[tmp].r<=b&&now==p[tmp].l)
                {
                    p[tmp].cnt++;    
                }
                else
                {
                    if(p[tmp].cnt) xiu(tmp);
                    if(p[tmp].flag)
                    {
                        
                        continue;
                    }
                    for(ri j=now;j<=min(p[tmp].r,b);j++)
                    {
                        p[tmp].val-=val[j];
                        val[j]=sqrt(val[j]);
                        p[tmp].val+=val[j];
                    }
                    if(p[tmp].r-p[tmp].l+1==p[tmp].val) p[tmp].flag=1;
                }
                    
            }
        }
        else
        {
            long long ans=0;
            for(ri now=a;now<=b;now=p[now/d+1].r+1)
            {
                int tmp=now/d+1;
                if(p[tmp].r<=b&&now==p[tmp].l)
                {
                    if(p[tmp].flag) ans+=p[tmp].val;
                    else 
                    {
                        if(p[tmp].cnt) xiu(tmp);
                        ans+=p[tmp].val;    
                    }    
                }
                else
                {
                    if(p[tmp].cnt) xiu(tmp);
                    if(p[tmp].flag)
                    {
                        ans+=min(p[tmp].r,b)-now+1;
                     
                        continue;
                    }
                    for(ri j=now;j<=min(p[tmp].r,b);j++)
                    {
                        ans+=val[j];
                    }
                }    
            
            }
            cout<<ans<<"\n";
        }
    }
    return 0;

    
} 
View Code

 

posted @ 2022-11-15 18:40  VxiaohuanV  阅读(22)  评论(0编辑  收藏  举报