CCPC-Wannafly Winter Camp Day5 (Div2, onsite) Sorting(线段树)

题目链接

题意

对序列进行三种操作:

        1、区间求和。

        2、将区间小于等于$x$的数不改变相对顺序的前提下放到$x$左边,用同样规则将比$x$大的放到右边。

        3、将区间大于$x$的数不改变相对顺序的前提下放到$x$左边,用同样规则将小于等于$x$的放到右边。

思路

将小于等于和大于$x$的数字分成两类,发现同类之间的相对顺序不改变,可以通过线段树维护区间内同类数字的数量和位置来获得区间真实值,使用前缀和维护两类数字序列的任意子段和。

代码

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>

#define IOS      ios::sync_with_stdio(0),cin.tie(0);
#define DBG(x)   cerr << #x << " = " << x << endl;

using namespace std;

typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;

const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double pi  = acos(-1.0);

void file(){
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
}

namespace BakuretsuMahou{

    const int maxn = 2e5+5;

    int n,q,x;
    LL a[maxn];
    LL p1[maxn],p0[maxn],top1,top0;

    struct node{
        int l,r;
        LL val,laz;
    }tree[maxn<<2];

    void pushup(int u){
        tree[u].val=tree[u<<1].val+tree[u<<1|1].val;
    }

    void pushdown(int i,int len){
        if(tree[i].laz){
            tree[i<<1].laz=tree[i].laz;
            tree[i<<1|1].laz=tree[i].laz;
            tree[i<<1].val=(len-(len>>1))*(tree[i].laz-1);
            tree[i<<1|1].val=(len>>1)*(tree[i].laz-1);
            tree[i].laz=0;
        }
    }

    void build(int i,int l,int r){
        tree[i].l=l;
        tree[i].r=r;
        tree[i].laz=0;
        if(l == r){
            tree[i].val=a[r];
            return;
        }
        int mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        pushup(i);
    }

    void update(int i,int l,int r,int L,int R,int c){
        if(L <= l && r <= R){
            tree[i].val=(r-l+1)*c;
            tree[i].laz=c+1;
            return;
        }
        pushdown(i,r-l+1);
        int mid=(l+r)>>1;
        if(L <= mid)update(i<<1,l,mid,L,R,c);
        if(R > mid)update(i<<1|1,mid+1,r,L,R,c);
        pushup(i);
    }

    LL query(int i,int l,int r,int L,int R){
        LL res=0;
        if(L <= l && r <= R){
            res=tree[i].val;
            return res;
        }
        pushdown(i,r-l+1);
        int mid=(l+r)>>1;
        if(L <= mid)res+=query(i<<1,l,mid,L,R);
        if(R > mid)res+=query(i<<1|1,mid+1,r,L,R);
        return res;
    }

    void Explosion(){
        scanf("%d%d%d",&n,&q,&x);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i] > x)p1[++top1]=a[i],a[i]=1;
            else p0[++top0]=a[i],a[i]=0;
        }
        for(int i=2;i<=top1;i++)p1[i]+=p1[i-1];
        for(int i=2;i<=top0;i++)p0[i]+=p0[i-1];
        build(1,1,n);
        while(q--){
            int op,l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op == 1){
                int num1=query(1,1,n,l,r),num0=r-l+1-num1;
                int pre1=0,pre0=0;
                if(l > 1){
                    pre1=query(1,1,n,1,l-1);
                    pre0=l-1-pre1;
                }
                printf("%lld\n",p1[pre1+num1]-p1[pre1]+p0[pre0+num0]-p0[pre0]);
            }
            if(op == 2){
                int num1=query(1,1,n,l,r),num0=r-l+1-num1;
                update(1,1,n,l,l+num0-1,0);
                update(1,1,n,l+num0,r,1);
            }
            if(op == 3){
                int num1=query(1,1,n,l,r);
                update(1,1,n,l,l+num1-1,1);
                update(1,1,n,l+num1,r,0);
            }
        }
    }
}

int main(){
    //IOS
    //file();
    BakuretsuMahou::Explosion();
    return 0;
}

在$camp$补的第一个题,懒惰啊。

猜你喜欢

转载自www.cnblogs.com/DuskOB/p/10318364.html