abc371 f 线段树

F - Takahashi in Narrow Road
在这里插入图片描述我们可以发现,每次操作后,对于一段变化后的区间,其变为了一段公差为1的等差数列,所以我们如果把每个值减去对应的下标,那么对应的区间变化后,都为一个相同的值,这样就可以使用区间推平,用线段树进行维护即可,然后根据题目信息,每次计算出变化区间的左端点和右端点即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
const int maxv = 4e6 + 5;
typedef pair<ll, ll> pll;
typedef array<int,3> ar;
// #define endl "\n"
int mod=1e9+7;
const int inf=0x3f3f3f3f;

struct node
{
    ll l,r,sum,add;
    #define l(x) tr[x].l
    #define r(x) tr[x].r
    #define sum(x) tr[x].sum
    #define add(x) tr[x].add
}tr[N*4];

int a[N];


void update(int p)
{
    sum(p)=sum(p*2)+sum(p*2+1);
}


void build(int p,int l,int r)
{
    if(l==r){
        tr[p]={l,r,a[l],0};
        return ;
    }
    l(p)=l,r(p)=r;
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    update(p);
}

void pushdown(int p)
{
    if(add(p)){
        sum(p*2)=(r(p*2)-l(p*2)+1)*add(p);
        sum(p*2+1)=(r(p*2+1)-l(p*2+1)+1)*add(p);
        add(p*2)=add(p);
        add(p*2+1)=add(p);
        add(p)=0;
    }
}

void modify(int p,int l,int r,int tag)
{
    if(l<=l(p)&&r(p)<=r){
        add(p)=tag;
        sum(p)=(r(p)-l(p)+1)*tag;
        return ;
    }
    pushdown(p);
    int mid=(l(p)+r(p))/2;
    if(l<=mid) modify(p*2,l,r,tag);
    if(r>mid) modify(p*2+1,l,r,tag);
    update(p);
    
}

ll query(int p,int l,int r)
{
    if(l<=l(p)&&r(p)<=r){
        return sum(p);
    }
    pushdown(p);
    int mid=(l(p)+r(p))/2;
    ll res=0;
    if(l<=mid) res+=query(p*2,l,r);
    if(r>mid) res+=query(p*2+1,l,r);
    return res;
}

void solve()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],a[i]-=i;
    int q;
    cin>>q;
    auto get=[&](int x,int l,int r)
    {
        int ans=0;
        while(l<=r){
            int mid=(l+r)/2;
            if(query(1,mid,mid)>=x){
                ans=mid,r=mid-1;
            }
            else l=mid+1;
        }
        return ans;
    };
    auto get1=[&](int x,int l,int r)
    {
        int ans=0;
        while(l<=r){
            int mid=(l+r)/2;
            if(query(1,mid,mid)<=x){
                ans=mid,l=mid+1;
            }
            else r=mid-1;
        }
        return ans;
    };
    ll ans=0;
    build(1,1,n);
    while(q--){
        ll x,y;
        cin>>x>>y;
        y-=x;
        ll val=query(1,x,x);
        int l,r;
        if(val<=y){
            l=x,r=get1(y,x,n);

        }
        else{
            l=get(y,1,x),r=x;
        }
        // cout<<val<<" "<<l<<" "<<r<<endl;
        ans+=abs(query(1,l,r)-y*(r-l+1));
        modify(1,l,r,y);
    }
    cout<<ans<<endl;
}


int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin>>t;
	while (t--)
	{
		solve();
	}
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值