[树状数组] Jzoj P4737 金色丝线将瞬间一分为二
题解
- 先定义两个数组rank1和rank2表示以x或y坐标从小到大排序后第i个点的排名
- 那么弄出这两个数组之后,每次加上做到的点i到所有前面的点的距离
- 可以用两个树状数组来做,一个记录的是x坐标一个是y坐标
- 那么,就是先将1~rank1[i]排名的遗体的个数和x坐标和求出来,总距离加上num*x[i]-sumx
- 然后还有求出rank1[i]+1~n排名的遗体的个数和x坐标和求出来,总距离就是sumx-num*x[i]
- y的做法同上
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 long long sz1[600010],sz2[600010],x[600010],y[600010],s,num,sumx,sumy,d; 6 int n,cnt1[600010],cnt2[600010],rank1[600010],rank2[600010],d1[600010],d2[600010]; 7 bool cmpx(int a,int b) { return x[a]<x[b]; } 8 bool cmpy(int a,int b) { return y[a]<y[b]; } 9 void insert1(int x,int y) 10 { 11 for (;x<=n;x+=x&-x) sz1[x]+=y,cnt1[x]++; 12 } 13 void insert2(int x,int y) 14 { 15 for (;x<=n;x+=x&-x) sz2[x]+=y,cnt2[x]++; 16 } 17 long long getsum1(int x,long long &y) 18 { 19 long long s=0; 20 for (;x;x-=x&-x) s+=sz1[x],y+=cnt1[x]; 21 return s; 22 } 23 long long getsum2(int x,long long &y) 24 { 25 long long s=0; 26 for (;x;x-=x&-x) s+=sz2[x],y+=cnt2[x]; 27 return s; 28 } 29 long long query1(int l,int r,long long &num) 30 { 31 long long tot=0,s=getsum1(r,num)-getsum1(l-1,tot); 32 num-=tot; 33 return s; 34 } 35 long long query2(int l,int r,long long &num) 36 { 37 long long tot=0,s=getsum2(r,num)-getsum2(l-1,tot); 38 num-=tot; 39 return s; 40 } 41 int main() 42 { 43 scanf("%d%lld",&n,&d); 44 for (int i=1;i<=n;i++) 45 { 46 scanf("%lld%lld",&x[i],&y[i]); 47 d1[i]=d2[i]=i; 48 } 49 sort(d1+1,d1+n+1,cmpx); 50 sort(d2+1,d2+n+1,cmpy); 51 for (int i=1;i<=n;i++) rank1[d1[i]]=i,rank2[d2[i]]=i; 52 for (int i=1;i<=n;i++) 53 { 54 num=0,sumx=query1(1,rank1[i],num),s+=num*x[i]-sumx; 55 num=0,sumx=query1(rank1[i],n,num),s+=sumx-num*x[i]; 56 num=0,sumy=query2(1,rank2[i],num),s+=num*y[i]-sumy; 57 num=0,sumy=query2(rank2[i],n,num),s+=sumy-num*y[i]; 58 if (s>d) 59 { 60 printf("%d",i); 61 return 0; 62 } 63 insert1(rank1[i],x[i]),insert2(rank2[i],y[i]); 64 } 65 printf("-1"); 66 return 0; 67 }