【树状数组】【权值分块】bzoj2352 Stars

经典问题:二维偏序。给定平面中的n个点,求每个点左下方的点的个数。

因为 所有点已经以y为第一关键字,x为第二关键字排好序,所以我们按读入顺序处理,仅仅需要计算x坐标小于<=某个点的点有多少个就行。

这就是所说的:n维偏序,一维排序,二维树状数组,三维 分治 Or 树状数组套平衡树……

<法一>树状数组。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 struct POINT
 6 {
 7     int x,y;
 8 };
 9 int n,d[3200001],ji[1500001],m;
10 POINT star[1500001];
11 bool cmp(const POINT &a,const POINT &b)
12 {
13     if(a.x<b.x)
14       return true;
15     else if(a.x>b.x)
16       return false;
17     else if(a.y<b.y)
18       return true;
19     return false;
20 }
21 int lowbit(int x)
22 {
23     return x&(-x);
24 }
25 void update(int x,int delta)
26 {
27     for(;x<=m;x+=lowbit(x))
28       d[x]+=delta;
29 }
30 int getsum(int x)
31 {
32     int res=0;
33     for(;x>0;x-=lowbit(x))
34       res+=d[x];
35     return res;
36 }
37 int main()
38 {
39     scanf("%d",&n);
40     for(int i=1;i<=n;i++)
41       {
42           scanf("%d%d",&star[i].x,&star[i].y);
43           star[i].y++;
44           m=max(m,star[i].y);
45       }
46     for(int i=1;i<=n;i++)
47       {
48           update(star[i].y,1);
49           ji[getsum(star[i].y)-1]++;
50       }
51     for(int i=0;i<n;i++)
52       printf("%d\n",ji[i]);
53     return 0;
54 }

<法二>权值分块。我会说比树状数组还快将近一倍?

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,x[15001],y[15001],LIMIT,r[200],l[200],num[33000],sumv[200],sz,sum,rank[33000],b[33000];
 6 void makeblock()
 7 {
 8     sz=(int)sqrt((double)LIMIT); if(!sz) sz=1; r[0]=-1;
 9     for(sum=1;sum*sz<LIMIT;sum++)
10       {
11           l[sum]=r[sum-1]+1;
12           r[sum]=sum*sz;
13           for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
14       }
15     l[sum]=r[sum-1]+1;
16     r[sum]=LIMIT;
17     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
18 }
19 int query(const int &V)
20 {
21     int cnt=0;
22     for(int i=1;i<num[V];i++) cnt+=sumv[i];
23     for(int i=l[num[V]];i<=V;i++) cnt+=b[i];
24     ++b[V]; ++sumv[num[V]];
25     return cnt;
26 }
27 int main()
28 {
29     scanf("%d",&n);
30     for(int i=1;i<=n;i++)
31       {
32           scanf("%d%d",&x[i],&y[i]);
33           LIMIT=max(LIMIT,x[i]);
34       } makeblock();
35     for(int i=1;i<=n;i++) ++rank[query(x[i])];
36     for(int i=0;i<n;i++) printf("%d\n",rank[i]);
37     return 0;
38 }
时间: 2024-10-10 07:13:40

【树状数组】【权值分块】bzoj2352 Stars的相关文章

[树状数组][权值线段树] Codeforces 1093E Intersection of Permutations

题目描述 You are given two permutations aa and bb , both consisting of nn elements. Permutation of nn elements is such a integer sequence that each value from 11 to nn appears exactly once in it. You are asked to perform two types of queries with them: 1

树状数组的进阶运用(Stars 数星星)

英文原题 Problem Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the g

POJ 2481 树状数组 区间覆盖(POJ2352 Stars 的变形题)(线段化点)

0)学会将题目情景转化为自己熟悉的结构或模型. 题目大意: 每个奶牛有自己的一个区间,求每个奶牛的区间所覆盖的子区间个数(注意,真子集,相等的不算),按照输入的顺序输出. 转化: 要学会将题目情景转化为自己熟悉的模型或结构上.把每个区间的左端x值作为点的x坐标,右端x值作为点的y坐标,就可以把所有区间转化为一个二维坐标图上的点集,而此时每个点左上方的点(同Stars那道题目一样不包括自身)的个数,就是每个区间所覆盖的子区间的个数(对应题目要求,这里或许可以再变形). 同POJ2481 Stars

{POJ}{树状数组}

总结一下树状数组的题目: {POJ}{3928}{Ping Pong} 非常好的题目,要求寻找一个数组中满足A[i]<A[k]<A[j]的个数,其中i<k<j(或者相反).很巧妙的将题目转化为树状数组的思想,从A[k]考虑,则只需要寻找左边比自己小和右边比自己大的可能性(或者相反),这样就可以用树状数组来维护.思想的转变很重要. {POJ}{1990}{MooFest} n头牛,不同的听力值v,当i,j想要通话时,需要max(v(i),v(j))*(dist[i]-dist[j])

BZOJ 1227 [SDOI2009] 虔诚的墓主人 离线+树状数组+离散化

鸣谢:140142耐心讲解缕清了我的思路 题意:由于调这道题调的头昏脑涨,所以题意自己搜吧,懒得说. 方法:离线+树状数组+离散化 解析:首先深表本蒟蒻对出题人的敬(bi)意(shi).这道题简直丧心病狂,看完题后大脑一片空白,整个人都不好了,刚开始的思路是什么呢?暴力思想枚举每个墓碑,然后计算每个墓碑的虔诚度,然后再来统计.不过看看数据范围呢?10^9*10^9的矩阵,最多才10^5个树,光枚举就已经超时了,所以肯定不行.(不过要是考试真没思路我就那么搞了- -!) 然后也想到来枚举墓碑,不过

hdu-2852 KiKi&#39;s K-Number---二分+树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2852 题目大意: 题意:    给出三种操作,    0 在容器中插入一个数.    1 在容器中删除一个数.    2 求出容器中大于a的第k大元素. 解题思路: 用树状数组维护每个值,插入数字是add(x, 1),删除时add(x, -1) 查询第k大时,先判断是否存在,存在的话直接根据树状数组sum值的单调性二分法求解即可 1 #include<iostream> 2 #include&l

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons

【BZOJ4167】永远的竹笋采摘 分块+树状数组

[BZOJ4167]永远的竹笋采摘 题解:我们考虑有多少点对(a,b)满足a与b的差值是[a,b]中最小的.以为是随机数据,这样的点对数目可能很少,实测是O(n)级别的,那么我们已知了有这么多可能对答案造成贡献的点对,如何将它们求出来呢? 考虑分块,因为所有数大小在[1,n]中,我们可以对于每个块,预处理出整个块到所有数的最小差值.然后从右往左枚举每一个点,再枚举右面所有的块,如果这个块到当前数的差值比之前的要小,那就暴力进入块中扫一遍.与此同时,我们需要知道是否已经存在这样的点对,被当前的点对