P3992 [BJOI2017]开车

题意:

在这里插入图片描述

题解:

我们要先将问题转换
圈是车,x是加油站。红色部分为车移动的路线
数组a是车数量的前缀和
数组b是加油站的前缀和
而a[i]与b[i]的差的绝对值就是对应的红色路被走的次数
在这里插入图片描述
现在车发生位置移动,b数组没有影响,a数组i到j这段整体减一
在这里插入图片描述
现在我们要做的就是维护a序列,支持区间+1/-1,询问∑| a[i] - b[i] |
线段树不能实现
用分块实现
实现过程:
按照下标分块,每块按照a[i] - b[i] 排序
在这里插入图片描述

代码:

代码为借鉴

#pragma optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 150005
#define MAXB 2005
using namespace std;
typedef long long ll;

int N,B,Q;
int a[MAXN], w[MAXN];
map<int,int> mp;
map<int,int>::iterator it;
map<int,int> id;

int q[MAXN][2];
struct Node{
    int w,val,id,sw;
    Node(int id=0, ll val=0, int w=0):id(id), val(val), w(w){}

    bool operator < (const Node& n1) const{
        return val < n1.val;
    }
};
vector<Node> adj[MAXN];
ll ANS = 0, ans[MAXN], base[MAXN];

void rebuild(int id){
    ANS -= ans[id]; ans[id] = 0;
    sort(adj[id].begin(), adj[id].end());
    for(int k=0;k<adj[id].size();k++){
        ans[id] += abs((ll)adj[id][k].val + base[id]) * adj[id][k].w;

        if(k==0) adj[id][k].sw = adj[id][k].w;
        else adj[id][k].sw = adj[id][k-1].sw + adj[id][k].w;
    }
    ANS += ans[id];
}

void work(int l, int r, int f){
    int idl = l/B, idr = r/B;
    if(idl==idr){
        for(int k=0;k<adj[idl].size();k++){
            if(l<=adj[idl][k].id && adj[idl][k].id<=r){
                if(f==0) adj[idl][k].val -= 1;
                if(f==1) adj[idl][k].val += 1;
            }
        }
        rebuild(idl);
    }
    else{
        if(idl+1<idr){
            for(int id=idl+1;id<idr;id++){
                //
                int lb = 0, rb = adj[id].size()-1, mid;
                if(f==0){
                    if(adj[id][rb].val + base[id] <= 0){
                        ans[id] += adj[id][rb].sw;
                        ANS += adj[id][rb].sw;
                        base[id] -= 1;
                        continue;
                    }
                    while(lb < rb){
                        mid = (lb + rb)/2;
                        if(adj[id][mid].val + base[id] > 0) rb = mid;
                        else lb = mid + 1;
                    }

                    base[id] -= 1;
                    int p = rb;
                    if(p==0){
                        ans[id] -= adj[id][adj[id].size()-1].sw;
                        ANS -= adj[id][adj[id].size()-1].sw;
                    }
                    else{
                        ans[id] += adj[id][p-1].sw;
                        ANS += adj[id][p-1].sw;
                        ans[id] -= adj[id][adj[id].size()-1].sw - adj[id][p-1].sw;
                        ANS -= adj[id][adj[id].size()-1].sw - adj[id][p-1].sw;
                    }
                }
                else{
                    if(adj[id][rb].val + base[id] < 0){
                        ans[id] -= adj[id][rb].sw;
                        ANS -= adj[id][rb].sw;
                        base[id] += 1;
                        continue;
                    }
                    while(lb < rb){
                        mid = (lb + rb)/2;
                        if(adj[id][mid].val + base[id] >= 0) rb = mid;
                        else lb = mid + 1;
                    }

                    base[id] += 1;
                    int p = rb;
                    if(p==0){
                        ans[id] += adj[id][adj[id].size()-1].sw;
                        ANS += adj[id][adj[id].size()-1].sw;
                    }
                    else{
                        ans[id] -= adj[id][p-1].sw;
                        ANS -= adj[id][p-1].sw;
                        ans[id] += adj[id][adj[id].size()-1].sw - adj[id][p-1].sw;
                        ANS += adj[id][adj[id].size()-1].sw - adj[id][p-1].sw;
                    }
                }
            }
        }

        for(int k=0;k<adj[idl].size();k++){
            if(l<=adj[idl][k].id && adj[idl][k].id<=r){
                if(f==0) adj[idl][k].val -= 1;
                if(f==1) adj[idl][k].val += 1;
            }
        }
        rebuild(idl);

        for(int k=0;k<adj[idr].size();k++){
            if(l<=adj[idr][k].id && adj[idr][k].id<=r){
                if(f==0) adj[idr][k].val -= 1;
                if(f==1) adj[idr][k].val += 1;
            }
        }
        rebuild(idr);
    }
}

int pos[MAXN];

int main(){
    scanf("%d", &N);
    int x;
    for(int i=1;i<=N;i++){
        scanf("%d", &x);
        pos[i] = x;
        mp[x] += 1;
    }
    for(int i=1;i<=N;i++){
        scanf("%d", &x);
        mp[x] -= 1;
    }

    scanf("%d", &Q);
    for(int i=1;i<=Q;i++){
        scanf("%d%d", &q[i][0], &q[i][1]);
        if(mp.count(q[i][1])==0) mp[q[i][1]] = 0;
    }

    int n = 0, x0 = 0;
    for(it=mp.begin(); it!=mp.end(); ++it){

        x = it->first;
        id[x] = ++n;

        w[n-1] = x - x0;
        a[n] = a[n-1] + it->second;

        x0 = x;
    }

    N = n; B = sqrt(N); 
    //cerr<<"B = "<<B<<endl;
    for(int i=1;i<=N;i++){
        adj[i/B].push_back(Node(i,a[i],w[i]));
    }

    for(int id=0;id<=N/B;++id){
        rebuild(id);
    }

    printf("%lld\n", ANS);

    int l,r;
    for(int i=1;i<=Q;i++){
        l = id[pos[q[i][0]]];
        r = id[q[i][1]];
        pos[q[i][0]] = q[i][1];
        //cerr<<"work "<<l<<" "<<r<<endl;
        if(l < r) work(l, r-1, 0);
        if(l > r) work(r, l-1, 1);
        printf("%lld\n", ANS);
    }

    return 0;
}