【POJ】1990-MooFest(树状数组or线段树)

树状数组和线段树的解法比较,感觉不论在内存还是时间上都是树状数组占优

大题思路对 v从小到大进行排序,之后找之前的(也就是比v小的坐标)

v * sum(abs(xi - x)) 这样的话 abs无法处理,我们用另外一个树状数组记录在x ~ y区间牛的个数,之前那个记录在x ~ y区间内牛的坐标和


Accepted
484 79
C++
1131  

树状数组代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 22222;
int C1[maxn],C2[maxn];
int n = 20005,nn;
struct Cow{
    int v,x;
    friend bool operator < (Cow p,Cow q){
        return p.v < q.v;
    }
}cow[maxn];
int lowbit(int x){
    return x & -x;
}
int sum(int C[],int x){
    int ret = 0;
    while(x > 0){
        ret += C[x];
        x -= lowbit(x);
    }
    return ret;
}
void add(int C[],int x,int d){
    while(x <= n){
        C[x] += d;
        x += lowbit(x);
    }
}
int main(){
    scanf("%d",&nn);
    memset(C1,0,sizeof(C1));
    memset(C2,0,sizeof(C2));
    for(int i = 0; i < nn; i++)
        scanf("%d%d",&cow[i].v,&cow[i].x);
    sort(cow,cow + nn);
    LL ans = 0;
    for(int i = 0; i < nn; i++){
        int x = cow[i].x,v = cow[i].v;
        int m1 = sum(C1,x),n1 = sum(C2,x);
        int m2 = sum(C1,n) - m1,n2 = sum(C2,n) - n1;
        ans += (((LL)n1 * x - m1) + ((LL)m2 - n2 * x)) * v;
        add(C1,x,x);
        add(C2,x,1);
    }
    printf("%I64d\n",ans);
    return 0;
}
I
Accepted
932 110
C++
1723  

线段树代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 20005;
typedef long long LL;
/*线段树解法*/
#define lson (pos<<1)
#define rson (pos<<1|1)
int v1[maxn << 2],v2[maxn << 2];
struct Node{
    int x,v;
    friend bool operator < (Node p,Node q){
        return p.v < q.v;
    }
}node[maxn];
void build(){
    memset(v1,0,sizeof(v1));
    memset(v2,0,sizeof(v2));
}
void pushup(int v[],int pos){
    v[pos] = v[lson] + v[rson];
}
void update(int v[],int L,int R,int aim,int pos,int value){
    if(L == R){
        v[pos] += value;
        return;
    }
    int mid = (L + R) >> 1;
    if(aim <= mid)
        update(v,L,mid,aim,lson,value);
    else
        update(v,mid + 1,R,aim,rson,value);
    pushup(v,pos);
}
int query(int v[],int L,int R,int l,int r,int pos){
    if(l <= L && R <= r){
        return v[pos];
    }
    int mid = (L + R) >> 1;
    int ans = 0;
    if(l <= mid)
        ans += query(v,L,mid,l,r,lson);
    if(r  > mid)
        ans += query(v,mid + 1,R,l,r,rson);
    return ans;
}
int main(){
    build();
    int n,max_size = 0;
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%d%d",&node[i].v,&node[i].x);
        max_size = max(max_size,node[i].x) + 1;
    }
    sort(node,node + n);
    LL ans = 0;
    for(int i = 0; i < n; i++){
        int x = node[i].x,v = node[i].v;
        ans += ((LL)(x * query(v2,1,max_size,1,x,1)) - (LL)(query(v1,1,max_size,1,x,1))) * v;
        ans += ((LL)(query(v1,1,max_size,x,max_size,1)) - (LL)(query(v2,1,max_size,x,max_size,1) * x)) * v;
        //printf("%d %I64d\n",i,ans);
        update(v2,1,max_size,x,1,1);
        update(v1,1,max_size,x,1,x);
    }
    printf("%I64d\n",ans);
    return 0;
}
时间: 2024-10-12 00:04:59

【POJ】1990-MooFest(树状数组or线段树)的相关文章

浅谈二维中的树状数组与线段树

一般来说,树状数组可以实现的东西线段树均可胜任,实际应用中也是如此.但是在二维中,线段树的操作变得太过复杂,更新子矩阵时第一维的lazy标记更是麻烦到不行. 但是树状数组在某些询问中又无法胜任,如最值等不符合区间减法的询问.此时就需要根据线段树与树状数组的优缺点来选择了. 做一下基本操作的对比,如下图. 因为线段树为自上向下更新,从而可以使用lazy标记使得矩阵的更新变的高校起来,几个不足就是代码长,代码长和代码长. 对于将将矩阵内元素变为某个值,因为树状数组自下向上更新,且要满足区间加法等限制

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

树状数组与线段树

一:树状数组 树状数组是对一个数组改变某个元素和求和比较实用的数据结构.两中操作都是O(logn). 需求:有时候我们需要频繁地求数组的前k项和或者求数组从小标i到j的和,这样每次最坏情况下的时间复杂度就会为O(N),这样效率太低了.而树状数组主要就是为了解决这样一个问题.树状数组在求和及修改都可以在O(lgN)时间内完成. 树状数组需要额外维护一个数组,我们设为C[N],原数组为A[N], 其中每个元素C[i]表示A[i-2^k+1]到A[i]的和,这里k是i在二进制时末尾0的个数.注意通过位

[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = = 嗯就是这样,代码长度= =我写了260行......Debug了n小时= = 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #in

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

HDU 1566 Color the ball(树状数组or线段树)

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11387    Accepted Submission(s): 5680 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"

BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树

题意:链接 方法:树状数组套线段树 解析: 这题基本上写的都是什么CDQ点分治,主席树之类的,然而这我都并不会,所以写了一发平衡树套线段树想卡时卡过去,然而我并没有得逞,T的不要不要的,这里用平衡树套线段树的方法参见我的题解:排队.这道题比那道更要简单. 然后我就打算弃坑了~不过看140142做这道题做的热火朝天的,还是打算回来做一下,yy下树状数组套线段树,然后去看hz的题解,只看懂他写理论部分了,代码部分不知所云,所以还是还是得yy.引用理论部分. 删除某个数,只要统计它之前还存在的比它大的

HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

思路:本题因为是点修改,所以我们可以用线段树或者是树状数组了.线段树的基本操作我在我的代码中会具体体现,关键是要理解下面这幅图,具体的思想大家可以去看看其他的资料 线段树AC代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define N 50005 int num

poj 3468 A Simple Problem with Integers 树状数组 或 线段树

题目链接:http://poj.org/problem?id=3468 一般说来 树状数组是 [单点更新 区间查询] 而本题是“区间更新 区间查询” 所以要改成维护前缀和 推公式的过程见<挑战程序设计竞赛>第181~182面 代码中bit0是i的零次项 bit1是i的一次项 以后以此类推 在[l, r]加数的时候 写出公式 在l的地方 一次项及以上的直接写 然后在零次项那减去 在r的地方 一次项及以上的减掉之前加上的 然后再零次项那加上“公式化简之后的最终结果 减去 之前在零次项加的那一项”