首页 > 代码库 > 用堆操作不断加入点来找到每个点对应所包含的值的个数的理解
用堆操作不断加入点来找到每个点对应所包含的值的个数的理解
首先还是要清楚一下堆操作的代码,毕竟线段树打多了,打堆的时候总会往线段树方向靠近
首先是建堆:
D=1;
for(;D<maxn+2;D<<=1);
然后给堆赋予值就可以了
查找区间段的和:
int query(int s,int t)
{
int i=D+s-1,j=D+t+1,ans=0;
for(;i^j^1;i>>=1,j>>=1){
if(~i&1) ans+=sum[i^1];
if(j&1) ans+=sum[j^1];
}
return ans;
}
更新操作:
void update(int i)
{
for(;i^1;i>>=1)
sum[i>>1]=sum[i]+sum[i^1];
}
之前也做了一道star level的题写成了博客,这里继续来写一遍,就是问对于一个星星的位置,比其x小于等于和y小于等于的点有多少个
这里我们所采取的是先进行一维上的排序,然后排好序后用另一维度来建树
如星星的题目已经以y的大小先后排好序了,那我们就省事了
我们从第一个节点不断添加进去,来找比它x小的数有几个,每次添加一个x,都要tree[D+x]++,再进行更新操作,因为后面的点是绝对不会影响到前面的点的
所以是可以这样做的:
第二题:
SPOJ RATING
这道题目也是两个维度,不过如果出现一样的值的话,者之间是不算谁比谁大的,这是跟星星不一样的地方
所以我们排好序后,每次添加点进入的时候还需要判断是否与前一个点值完全相同,如果相同不访问,直接继承前面一个点的值就可以了,然后再做更新
同时星星的点是题目本身按顺序给出的,而这里是乱序的,我们需要事先排好序然后不断添入点
我采取的方法是,建立结构体,除2维的数据外,还需记录id号,不然没法记录每个位置比别人大的个数
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define N 300005 6 int sum[N<<2],D,maxn; 7 struct Edge{ 8 int x,y,id; 9 bool operator<(const Edge &m)const10 {11 return x==m.x?y<m.y:x<m.x;12 }13 }e[N];14 void update(int i)15 {16 for(;i^1;i>>=1)17 sum[i>>1]=sum[i]+sum[i^1];18 }19 int query(int s,int t)20 {21 int i=D+s-1,j=D+t+1,ans=0;22 for(;i^j^1;i>>=1,j>>=1){23 if(~i&1) ans+=sum[i^1];24 if(j&1) ans+=sum[j^1];25 }26 return ans;27 }28 int main()29 {30 int n,ans[N];31 maxn=0;32 memset(sum,0,sizeof(sum));33 scanf("%d",&n);34 for(int i=0;i<n;i++){35 scanf("%d%d",&e[i].x,&e[i].y);36 maxn=max(maxn,e[i].y);37 e[i].id=i;38 }39 D=1;40 for(;D<maxn+2;D<<=1);41 sort(e,e+n);42 int k;43 for(int i=0;i<n;i++){44 if(i>1&&e[i].x==e[i-1].x&&e[i].y==e[i-1].y){45 }46 else{47 k=query(1,e[i].y);48 }49 ans[e[i].id]=k;50 sum[D+e[i].y]++;51 update(D+e[i].y);52 }53 for(int i=0;i<n;i++)54 printf("%d\n",ans[i]);55 return 0;56 }