标签:text 读者 code under 必须 并且 模拟 sans nbsp
在看之前,你必须了解树状数组的基本函数
inline ll lowbit(ll x) { return x&(-x); } inline void insert(ll x,ll y)//加入 { while(x<=n) { sum[x]+=y; x+=lowbit(x); } } inline ll findout(ll x)//查找 { ll ans=0; while(x) { ans+=sum[x]; x-=lowbit(x); } return ans; } inline ll cmp(oh a,oh b)//排序 { if(a.v==b.v) return a.num<b.num; else return a.v<b.v; }
首先,假如求有多少在a前面的数比a小;
举例: 1 4 2 3 5
然后有5个空位置, _ _ _ _ _ 为sum[5]
第一步 求出sum[1]前缀,答案是0;
插入1, 1 _ _ _ _
第二步 求出sum[4]前缀,答案是1;
插入4, 1 _ _ 4 _
第二步 求出sum[2]前缀,答案是1;
插入4, 1 2 _ 4 _
..........................
这样不断进行下去sum[i]就是 有多少在i前面的数比a小;
所以就转化成了求前缀和的题目了,自然就想到树状数组了;
但是输入的几个数可能会非常大,那么sum数组的下标就会爆;
我们只需知道每个数的大小关系,并不需要知道具体值,所以在处理之前可以离散化;
//离散化 for(ll i=1;i<=n;i++) { a[i].v=read(); a[i].num=i;//将每一个数的位置记下 } sort(a+1,a+n+1,cmp);//从小到大排序, //这样每个数都有顺序了,并且每个数对应的位置没有改变 for(ll i=1;i<=n;i++) b[a[i].num]=i;//把第i小的数位置上赋值为i
具体怎么实现,读者自行手动模拟;
按上面查找的思路
for(ll i=1;i<=n;i++) { ll x=findout(b[i]); ans[i]=x;//先求值,再插入,不然会把自己也算进去的 insert(b[i],1); }
则反之
for(ll i=n;i>=1;i--) { ll x=findout(b[i]); ans[i]=x;//反之 insert(b[i],1); }
这样就ok了
标签:text 读者 code under 必须 并且 模拟 sans nbsp
原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/13193271.html