zoukankan      html  css  js  c++  java
  • 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 可以差分数列的方式做的

  • 相关阅读:
    JS创建类的方法--简单易懂有实例
    CommonJS, AMD, CMD是什么及区别--简单易懂有实例
    JS回调函数--简单易懂有实例
    单链表应用(2)--使用快慢指针,如何判断是否有环,环在哪个节点
    单链表应用(1)--使用快慢指针,找链表中间值
    自定义线性结构-有序Map
    C++中final和override
    双向链表翻转
    检查“()”是否匹配并返回深度
    是否存在K
  • 原文地址:https://www.cnblogs.com/yejinru/p/2931515.html
Copyright © 2011-2022 走看看