第一次写博客 ,请多指教!
翻了翻前面的题解发现都是用树状数组来做,这里更新一个 线段树+离散化的做法:
其实这道题是没有必要用线段树的,树状数组就能够解决。但是个人感觉把线段树用熟了会比树状数组更有优势一点
不多废话
http://codeforces.com/contest/1311/problem/F 题目链接
题意是 给你一堆点的位置和他们运动的速度(可正可负),然后时间无限往后推的情况下问你他们之间所有点的最小距离之和。(不明白自行读题)
n的范围是2,200000; 显然单纯的一个一个看是不行的,那么自然想到用树状数组或者线段树来做。
接着可以想到
1.当两个点的位置xi ,xj满足 xi<xj 并且两个点的速度满足vi <=vj时 他们之间的最短距离一定是当前距离即xj与xi之差。
2.其余情况最短距离均为零(这一点很容易想)
那么就好办了
思路就是
1.先对每个点对按照位置从小到大进行排序
2.按照位置从前到后遍历这些点,进行建树。由当前点的速度确定在数组中的位置。
3.建树时每更新一个点之前可以求出这个点对答案的贡献 即:
ans+=(数组中位于当前点前面的点的数量(速度小于当前点速度的点的数量)×当前点的位置)- 前面所有点的位置值的和。
代码中的公式为 ans+=s[i].x*querye(1,x,1,n,1)-query(1,x,1,n,1);
由于是按照位置从前到后的顺序上树的,所以不必担心出现比当前点位置靠后的点;
而关于 统计速度小于当前点速度的点的数量 维护了一个he数组 查询用querye函数,而前面所有点的位置值的和则是最一般的线段树查询。
至于速度给的数据范围有点大,可以使用离散化将他们集中起来,以便作为下标进行更新。
上代码 (代码虽然看起来不是很简短但是基本都是模块化操作,耐心看下来就会感觉很容易理解)
https://www.cnblogs.com/LH2000/category/1656597.html 这里有一些本人写的相关模板函数,可以用作参考。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 #define rush! ios::sync_with_stdio(false);cin.tie(0); 6 const int inf = 0x3f3f3f3f; 7 const long long linf = 0x3f3f3f3f3f3f3f3f; 8 const int maxn=200005; 9 long long tree[maxn<<2]; //线段树 10 long long lsh[200005]; //离散化 数组 11 long long he[maxn<<2]; 12 struct trees{ 13 long long x, v; 14 }s[200005]; 15 bool cmp(const trees &x,const trees &y) 16 { 17 return x.x<y.x; 18 } 19 void pushup(int rt) 20 { 21 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; //用子节点更新父节点的位置值 22 he[rt]=he[rt<<1]+he[rt<<1|1]; //用子节点更新父节点数量值 23 } 24 25 void update(long long p,long long add,int l,int r,int rt) //上树 26 { 27 if(l==r) 28 { 29 tree[rt]+=add;//更新位置值 30 he[rt]++;//更新数量值 31 return; 32 } 33 int m=(l+r>>1); 34 if(p<=m) update(p,add,lson); 35 else update(p,add,rson); 36 pushup(rt); 37 } 38 39 long long query(int L,int R,int l,int r,int rt) //查询速度小于当前点速度的元素位置值的和 40 { 41 if(L<=l&&r<=R) 42 { 43 return tree[rt]; 44 } 45 int m=(l+r)>>1; 46 long long ret=0; 47 if(L<=m) ret+=query(L,R,lson); 48 if(R>m) ret+=query(L,R,rson); 49 return ret; 50 } 51 long long querye(int L,int R,int l,int r,int rt) //查询速度小于当前点速度的元素数量 52 { 53 if(L<=l&&r<=R) 54 { 55 return he[rt]; 56 } 57 int m=(l+r)>>1; 58 long long ret=0; 59 if(L<=m) ret+=querye(L,R,lson); 60 if(R>m) ret+=querye(L,R,rson); 61 return ret; 62 } 63 64 int main() 65 { 66 rush! //加速流 67 int n; 68 cin>>n; 69 for(int i=1;i<=n;i++) 70 { 71 cin>>s[i].x; 72 } 73 for(int i=1;i<=n;i++){ 74 cin>>s[i].v; 75 lsh[i]=s[i].v; 76 } 77 sort(lsh+1,lsh+n+1); //离散化排序 78 sort(s+1,s+n+1,cmp); 79 int cnt=unique(lsh+1,lsh+n+1)-lsh-1; //离散化数数 80 long long ans=0; 81 for(int i=1;i<=n;i++) 82 { 83 long long x=lower_bound(lsh+1,lsh+cnt+1,s[i].v)-lsh; //离散化 84 ans+=s[i].x*querye(1,x,1,n,1)-query(1,x,1,n,1); 85 update(x,s[i].x,1,n,1); //上树 86 } 87 cout<<ans<<endl; 88 }