zoukankan      html  css  js  c++  java
  • 【树状数组】【P2345】 奶牛集会

    传送门

    Description

    约翰的(N)头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出(max(V_i, V_j)~ imes~|X_i − X_j |) 的音量,其中(V_i)(V_j) 分别是第(i) 头和第(j),头奶牛的听力。假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

    Input

    第一行:单个整数(N)
    第二行到第(N + 1) 行:第(i + 1) 行有两个整数(V_i)(X_i)

    Output

    单个整数:表示所有奶牛产生的音量之和

    Sample Input

    4
    3 1
    2 5
    2 6
    4 3
    

    Sample Output

    57
    

    Hint

    所有数据(leq~20000)

    Solution

    发现枚举每两头奶牛是一件非常傻逼的事情。所以考虑对于每对奶牛,计算每头(v)更小(或更大)的牛的答案。
    为了破除掉(max)的干扰,可以按照(v)升序排序,这样扫一遍数组,就可以对于每个位置只计算它之前的牛的位置差最后乘v即可。
    考虑快速求出每个位置之前的x值。
    对于(i)之前的每个(x_j),共有两种,分别是大于(x_i)和小于(x_i)的。这样按照坐标建立树状数组可以统计他之前之后(x_j)的和以及个数,可以轻松算出该位置的ans。

    Code

    #include<cstdio>
    #include<algorithm>
    #define rg register
    #define ci const int
    #define cl const long long int
    
    typedef long long int ll;
    
    namespace IO {
    	char buf[90];
    }
    
    template<typename T>
    inline void qr(T &x) {
    	char ch=getchar(),lst=' ';
    	while(ch>'9'||ch<'0') lst=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst=='-') x=-x;
    }
    
    template<typename T>
    inline void write(T x,const char aft,const bool pt) {
    	if(x<0) x=-x,putchar('-');
    	int top=0;
    	do {
    		IO::buf[++top]=x%10+'0';
    		x/=10;
    	} while(x);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template<typename T>
    inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
    template<typename T>
    inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
    template<typename T>
    inline T mabs(const T a) {if(a<0) return -a;return a;}
    
    template<typename T>
    inline void mswap(T &a,T &b) {
    	T temp=a;a=b;b=temp;
    }
    
    const int maxn = 20010;
    const int upceil = 20000;
    
    struct Tree {
    	int cnt;ll sum;
    	inline Tree(int _a=0,ll _b=0) {cnt=_a,sum=_b;}
    };
    Tree frog[maxn];
    
    struct M {
    	int v,x;
    	inline bool operator<(const M &_others) const {
    		return this->v<_others.v;
    	}
    };
    M MU[maxn];
    
    int n;
    ll ans;
    
    inline int lowbit(ci x) {return x&((~x)+1);}
    
    void add(ci);
    Tree ask(int);
    
    int main() {
    	qr(n);
    	for(rg int i=1;i<=n;++i) {qr(MU[i].v);qr(MU[i].x);}
    	std::sort(MU+1,MU+1+n);
    	for(rg int i=1;i<=n;++i) {
    		Tree _ans1=ask(MU[i].x),_ans2=ask(upceil);
    		ans+=(1ll*_ans1.cnt*MU[i].x-_ans1.sum+(_ans2.sum-_ans1.sum)-1ll*(_ans2.cnt-_ans1.cnt)*MU[i].x)*MU[i].v;
    		add(MU[i].x);
    	}
    	write(ans,'
    ',true);
    	return 0;
    }
    
    Tree ask(int x) {
    	ll _sum=0;int _cnt=0;
    	while(x) {
    		_sum+=frog[x].sum;
    		_cnt+=frog[x].cnt;
    		x-=lowbit(x);
    	}
    	return Tree(_cnt,_sum);
    }
    
    void add(ci x) {
    	int _c=x;
    	while(_c<=upceil) {
    		frog[_c].sum+=x;
    		++frog[_c].cnt;
    		_c+=lowbit(_c);
    	}
    }
    

    Summary

    当计算被最大值限制时,可以考虑升/降序排序一次计算该位置从而避免最大值的(O(n^2))枚举

  • 相关阅读:
    Java核心技术
    浏览器地址栏输入url回车之后发生了些什么
    Java相关面试题总结+答案(十)
    Java相关面试题总结+答案(九)
    Java相关面试题总结+答案(八)
    Java相关面试题总结+答案(七)
    input type=‘file’方法
    禁止用户复制网页内容
    js添加背景水印
    angular双向绑定
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9597401.html
Copyright © 2011-2022 走看看