CF 276C Little Girl and Maximum Sum 差分数列,线段树,splay

题目here:
给出n个数,现在有m个区间询问l[i],r[i],问如何重新排列这n个数,使得
询问的和值最大

分析:
方法一:差分数列
一维的差分数列如下定义:
假设原数组为a[1]...a[n],a[0] = 0
差分数列数组为d[1]...d[n]
则d[i] = a[i]-a[i-1] (d数组初始化)
我们发现:a[i] = sigma(d[i])
所以我们对于区间[l,r]执行加同一个数的时候,我们可以执行
d[l] += val , d[r+1] -= val;
最终,我们可以用差分数列的累加和计算a[i]的值。

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)

string str;

const int X = 2e5+5;

int a[X],val[X];
int sum[X];

int main(){

#ifndef ONLINE_JUDGE
	freopen("sum.in","r",stdin);
	//freopen("sum.out","w",stdout);
#endif

    int n,m;
    while(cin>>n>>m){
        rep(i,n)
            scanf("%d",&val[i+1]);
        int x,y;
        memset(a,0,sizeof(a));
        while(m--){
            scanf("%d%d",&x,&y);
            a[x] ++;
            a[y+1] --;
        }
        for(int i=1;i<=n;i++)
            sum[i] = sum[i-1]+a[i];
        sort(sum+1,sum+n+1);
        sort(val+1,val+n+1);
        ll ans = 0;
        REP(i,1,n+1)
            ans += (ll)val[i]*sum[i];
        cout<<ans<<endl;
    }

	return 0;
}

  

方法二: 线段树做法:区间更新,询问总区间就可以把所有的数存在数组中了

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)

string str;

const int X = 2e5+5;

ll a[X];
int val[X];

struct node{
    int l,r;
    ll add;
    int mid(){
        return (l+r)>>1;
    }
}tree[X<<2];

void build(int l,int r,int rt){
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].add = 0;
    if(l==r)
        return;
    int mid = (l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}

void push_down(int rt){
    tree[rt<<1].add   += tree[rt].add;
    tree[rt<<1|1].add += tree[rt].add;
    tree[rt].add = 0;
}

void update(int l,int r,int rt){
    if(tree[rt].l==l&&tree[rt].r==r){
        tree[rt].add ++;
        return;
    }
    if(tree[rt].add)
        push_down(rt);
    int mid = tree[rt].mid();
    if(r<=mid)
        update(l,r,rt<<1);
    else if(l>mid)
        update(l,r,rt<<1|1);
    else
        update(l,mid,rt<<1),update(mid+1,r,rt<<1|1);
}

void query(int l,int r,int rt){
    if(tree[rt].l==tree[rt].r){
        a[l] = tree[rt].add;
        return;
    }
    if(tree[rt].add)
        push_down(rt);
    int mid = tree[rt].mid();
    if(l<=mid)
        query(tree[rt].l,mid,rt<<1);
    if(r>mid)
        query(mid+1,tree[rt].r,rt<<1|1);
}

int main(){

#ifndef ONLINE_JUDGE
	freopen("sum.in","r",stdin);
	//freopen("sum.out","w",stdout);
#endif
    int n,m,x,y;
    while(cin>>n>>m){
        rep(i,n)
            scanf("%d",&val[i+1]);
        build(1,n,1);
        while(m--){
            scanf("%d%d",&x,&y);
            update(x,y,1);
        }
        query(1,n,1);
        sort(a+1,a+n+1);
        sort(val+1,val+n+1);
        ll ans = 0;
        rep(i,n)
            ans += a[i+1]*val[i+1];
        cout<<ans<<endl;
    }

	return 0;
}

  

splay简单区间操作,增加两个额外的节点,然后对于区间[a,b]执行加一操作时,把第a小的节点splay至根,把第b+2小的节点splay至根(增加了两个节点。。)。然后把根的右儿子的左儿子lazy标记加一。

/*

splay简单区间操作,增加两个额外的节点,然后对于区间[a,b]执行加一操作时,
把第a小的节点splay至根,把第b+2小的节点splay至根(增加了两个节点。。)
然后把根的右儿子的左儿子lazy标记加一。

*/
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)

string str;

namespace Splay{

#define lx ch[x][0]
#define rx ch[x][1]
#define px pre[x]

#define ly ch[y][0]
#define ry ch[y][1]
#define py pre[y]

#define lz ch[z][0]

#define rt ch[root][1]
#define lrt ch[rt][0]

    const int MAXN = 2e5+5;

    int pre[MAXN],sz[MAXN],ch[MAXN][2];
    ll sum[MAXN],add[MAXN];
    int a[MAXN],n,m;
    int tot,root;

    inline void update(int x){
        sz[x] = sz[lx]+sz[rx]+1;
    }

    inline void push_down(int x){
        if(add[x]){
            if(lx)  add[lx] += add[x];
            if(rx)  add[rx] += add[x];
            sum[x] += add[x];
            add[x] = 0;
        }
    }

    inline int sgn(int x){
        return ch[px][1]==x;
    }

    inline void setc(int y,int d,int x){
        ch[y][d] = x;
        px = y;
    }

    inline void rot(int x,int d){
        int y = px;
        int z = py;
        push_down(y);
        push_down(x);
        setc(y,!d,ch[x][d]);
        if(z)   setc(z,sgn(y),x);
        pre[x] = z;
        setc(x,d,y);
        update(y);
    }

    inline void splay(int x,int goal=0){
        push_down(x);
        while(px!=goal){
            int y = px;
            int z = py;
            if(z==goal){
                rot(x,!sgn(x));
                break;
            }
            if(lz==y){
                if(ly==x)
                    rot(y,1),rot(x,1);
                else
                    rot(x,0),rot(x,1);
            }
            else{
                if(ry==x)
                    rot(y,0),rot(x,0);
                else
                    rot(x,1),rot(x,0);
            }
        }
        update(x);
        if(goal==0)
            root = x;
    }

    inline int get_Kth(int x,int k){
        push_down(x);
        int tmp = sz[lx]+1;
        if(tmp==k)
            return x;
        return k<tmp?get_Kth(lx,k):get_Kth(rx,k-tmp);
    }

    inline void modify(int l,int r){
        int x = get_Kth(root,l);
        int y = get_Kth(root,r+2);
        splay(x);
        splay(y,root);
        add[lrt] ++;
        update(rt);
        update(root);
    }

    inline void new_node(int &x,int y,ll v){
        x = ++tot;
        sum[x] = v;
        add[x] = 0;
        lx = rx = 0;
        pre[x] = y;
    }

    inline void build(int &x,int y,int l,int r){
        if(l>r) return;
        int mid = (l+r)>>1;
        new_node(x,y,0);
        build(lx,x,l,mid-1);
        build(rx,x,mid+1,r);
        update(x);
    }

    inline void dfs(int x){
        if(x){
            push_down(x);
            dfs(lx);
            dfs(rx);
        }
    }

    inline void init(){
        memset(ch,0,sizeof(ch));
        memset(pre,0,sizeof(pre));
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        memset(add,0,sizeof(add));

        root = tot = 0;
        new_node(root,0,0);
        new_node(rt,root,0);
        update(rt);
        update(root);
    }

    void dfs_debug(int x){
        if(x){
            cout<<x<<" "<<lx<<" "<<rx<<endl;
            dfs_debug(lx);
            dfs_debug(rx);
        }
    }

    void solve(){
        init();

        int n,m;
        cin>>n>>m;

        build(lrt,rt,0,n-1);
        update(rt);
        update(root);

        //dfs_debug(root);

        rep(i,n)
            scanf("%d",&a[i]);
        int x,y;
        while(m--){
            //debug;
            scanf("%d%d",&x,&y);
            modify(x,y);
        }

        dfs(root); // 把所有标记下沉

        sort(sum+1,sum+tot+1);
        reverse(sum+1,sum+tot+1);

        sort(a,a+n);
        reverse(a,a+n);

        ll ans = 0;
        rep(i,n)
            ans += a[i]*sum[i+1];
        cout<<ans<<endl;
    }

}using namespace Splay;

int main(){

#ifndef ONLINE_JUDGE
	freopen("sum.in","r",stdin);
	//freopen("sum.out","w",stdout);
#endif

    solve();

	return 0;
}

  

HOJ 2332 // poj 2894  Ancient Keyboard 可以差分数列的方式做的

原文地址:https://www.cnblogs.com/yejinru/p/2931515.html