zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
    }
  • 相关阅读:
    二分排序之三行代码
    最短路径—Floyd算法
    最小生成树 Kruskal算法
    最小生成树-Prim算法
    最短路径之迪杰斯特拉(Dijkstra)算法
    C函数指针
    Linux进程的实际用户ID和有效用户ID
    C++ 之Boost 实用工具类及简单使用
    ELK之消息队列选择redis_kafka_rabbitmq
    Python文件操作
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10092237.html
Copyright © 2011-2022 走看看