hdu3015树状数组 poj1990的离散化版本

都是一类题目,推导调试比较烦,想出来还是不难的

/*
给定n个点对,按一维升序排序一次,每个点的序号为Di,按二维升序排序一次,每个点的序号为Hi
求sum{w(i,j)}
w(i,j)=abs(Di-Dj)*min(Hi-Hj)

那么将所有的点按照H升序排列,两个树状数组,一个维护区间d的个数,一个维护区间d的总和
每个点的贡献值=树状数组中D小于其的+D大于其的abs

按升序遍历每个点后,将该点在树状数组中删掉
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
struct node {
    ll a,b;//x坐标,高度
    int num1,num2;//D,H
}t[maxn];
int n;
ll bitc[maxn],bitd[maxn];
int cmpa(node x,node y){return x.a<y.a;}
int cmpb(node x,node y){return x.b<y.b;}
int cmpc(node x,node y){return x.num2<y.num2;}
void add1(int x,int num){
    for(int i=x;i<=100000;i+=i&-i)
        bitc[i]+=num;
}
void add2(int x,int num){
    for(int i=x;i<=100000;i+=i&-i)
        bitd[i]+=num;
}
ll query1(int x){
    ll res=0;
    for(int i=x;i;i-=i&-i)
        res+=bitc[i];
    return res;
}
ll query2(int x){
    ll res=0;
    for(int i=x;i;i-=i&-i)
        res+=bitd[i];
    return res;
}
int main(){
    while(scanf("%d",&n)==1){
        memset(bitc,0,sizeof bitc);
        memset(bitd,0,sizeof bitd);
        for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i].a,&t[i].b);
        sort(t+1,t+1+n,cmpa);//按x坐标升序排列
        for(int i=1;i<=n;i++){
            if(i==1) t[i].num1=i;
            else if(t[i].a==t[i-1].a) t[i].num1=t[i-1].num1;
            else t[i].num1=i;
        }
        int max=t[n].num1;
        sort(t+1,t+1+n,cmpb);//按高度升序排列
        for(int i=1;i<=n;i++){
            if(i==1) t[i].num2=i;
            else if(t[i].b==t[i-1].b) t[i].num2=t[i-1].num2;
            else t[i].num2=i;
        }
        sort(t+1,t+1+n,cmpc);//按照h升序排列
        for(int i=1;i<=n;i++){add1(t[i].num1,1);add2(t[i].num1,t[i].num1);}

        ll ans=0;
        for(int i=1;i<n;i++){//最后一个点没有贡献度
            ll tmp1=query1(t[i].num1-1);//第i个点严格左边的
            ll tmp2=query2(t[i].num1-1);
            ll tmp3=query1(t[i].num1);
            ll tmp4=query2(t[i].num1);
            ans+=t[i].num2*(t[i].num1*tmp1-tmp2);
            ans+=t[i].num2*(query2(max+1)-tmp4-t[i].num1*(query1(max+1)-tmp3));//
            add1(t[i].num1,-1);
            add2(t[i].num1,-t[i].num1);
        }
        printf("%lld\n",ans);
    }
}

原文地址:https://www.cnblogs.com/zsben991126/p/10092237.html

时间: 2024-10-18 02:39:40

hdu3015树状数组 poj1990的离散化版本的相关文章

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

hdu3015树状数组

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3015 题意:给定n组数,每组数有值x和值h,求n组数两两的val的总和.将所有x和所有h分别离散化(不去重)变成x'和h',val(i,j)为abs(x'i-x'j)*min(hi',hj'). 如: x,    h——>x',h' 10,100——>1,1 50,500——>4,4 20,200——>3,3 20,100——>1,1 思路:只要把n*n优化成n*logn就可以过

HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化

http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则贡献加1 思路:主要的麻烦就是动态修改前缀和了.因为对于每个数字val.则找它祖先的话, <= k / val的数字,都是合法的.所以问题转化成求你现在dfs中保存的数字,有多少个是  <= k / val的,树状数组即可. 问题就是,数字太大了,这不适合树状数组,那么我们把每个数字离散成他们的下

nyoj 117 求逆序数 【树状数组】+【离散化】

这道题的解法真的很好!!! 思路:建立一个结构体包含val和id, val就是输入的数,id表示输入的顺序.然后按照val从小到大排序,如果val相等,那么就按照id排序. 如果没有逆序的话,肯定id是跟i(表示拍好后的顺序)一直一样的,如果有逆序数,那么有的i和id是不一样的.所以,利用树状数组的特性,我们可以简单的算出逆序数的个数. 如果还是不明白的话举个例子.(输入4个数) 输入:9 -1 18 5 输出 3. 输入之后对应的结构体就会变成这样 val:9 -1 18 5 id:  1  

cf1042d 树状数组逆序对+离散化

/* 给定一个数组,要求和小于t的段落总数 求前缀和 dp[i]表示以第i个数为结尾的小于t的段落总数,sum[i]-sum[l]<t; sum[i]-t<sum[l],所以只要找到满足条件的sum[l]数量即可 将sum排序,每次找到sum[i]-t的排名,大于它的就是l的数量 */ #include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 200005 ll tmp[maxn],

HDU 1166 —— 敌兵布阵 【树状数组 or 线段树】

http://acm.hdu.edu.cn/showproblem.php?pid=1166 需求: 1.点修改 2.区间求和 标准的BIT(二叉索引树,又名树状数组)问题,当然也可以用最基础的仅支持“点修改”的线段树来解决! 线段树版本: #include <cstdio> #include <iostream> #define INF 0x3f3f3f3f using namespace std; const int MAXN = 65536 + 5; // 65536 是最小

CCPC河南省赛B-树上逆序对| 离线处理|树状数组 + 线段树维护逆序对 + dfs序 + 离散化

B题地址:树上逆序对 有两个思路 方法一:线段树离线 + 树状数组或者线段树维护区间和 0:离散化,离线存储输入的operation操作序列. ①:先线段树在dfs序上离线处理好整一棵树:在dfs序上先查询"加入当前结点的逆序对权值和"并记录,再加入当前这个节点:dfs完毕后,就已经记录好每个结点的dfs序出入时间戳(转化成区间问题了)和每个 ②:使用树状数组或者新的线段树在dfs序上插入逆序对权值 为什么能这样呢?因为dfs序维护了每个结点遍历的顺序,每个结点的dfs序时间戳肯定比它

求逆序数数目(树状数组+离散化)

404在玩忍者印记(Mark of the Ninja)操纵忍者时遇到这样一个场景,两栋大楼之间有许多绳索,从侧面看,就像这个样子: 我们的忍者非常有好奇心,他可以观察到每个绳索的端点在两栋楼的高度,想知道这些绳索有多少个交点(图中黑色的点).他观察到不会建筑上不会有一点上有两个绳索,并且没有三条绳索共点. 输入描述 第一行:整数T,代表有T组数据. (1 <= T <= 100) 下一行:整数N,代表有N条绳索. (1 <= N <= 100000) 接下来Na行给出两个整数A_

ZOJ-2386 Ultra-QuickSort 【树状数组求逆序数+离散化】

Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input seque