题意是:有n个女士去参加舞会,每人有r,c,b三个属性,如果有比她每个属性值都大的人存在,她就跳楼(这人真想不开。。。)。给出n个人的属性,问有多少人跳楼。
思路:通过排序确定某个属性的大小关系,再通过树状数组或者线段树,统计。做法,先对任意一个属性从大到小排序(比如b),这个属性值相等情况下属性r从小到大排序,因为只有都大于的情况下才跳楼,这样即使在b相等情况下也不会错误统计结果。接下来的做法很巧妙,我是看了一天终于看懂了cf里面的那个代码。对属性r离散化,规则是找出r最大的标号1,依次类推,不是最小的标号1。为什么要这样呢。这一树状数组的应用是把r当作坐标,把c值当作权值,每个元素tree[i]代表前i个元素里面最大的权值是多少,这样按照排好序的数组扫描,首先看看bi之前是否有比他小的,即b值比他大的数,然后比较这个值是否比当前ci的值大。大的话就符合了每个属性都大于第i个人,那么跳。。。。然后向上更新最大值。好短的代码。。。。而且比赛时候写的,Orz。。。自己需要多训练。需要注意的是,这组代码里面的逆序离散化不是连续自然数,有充分属性b的情况下会断续,这并不影响结果,因为是要找之前有没有,只要相对的大小关系没有改变就可以。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep(i,a) for(int i = 0;i < a;i ++) using namespace std; const int N = 500010; struct node { int x, y, z; }rec[N]; bool operator < (node a,node b) { return a.x != b.x?a.x > b.x:a.y < b.y; } int h[N];//用于离散化的数组,同时后面用作树状数组 int main(){ int n; cin >> n; rep(i,n)cin >> rec[i].x; rep(i,n)cin >> rec[i].y,h[i] = rec[i].y; rep(i,n)cin >> rec[i].z; sort(h, h + n); sort(rec,rec + n); rep(i,n)rec[i].y = n - (lower_bound(h,h + n,rec[i].y) - h); memset(h,128,sizeof(h)); int ans = 0; rep(i,n) { int tmp = -0x7fffffff; for(int j = rec[i].y - 1;j; j -= j & -j)tmp = max(tmp, h[j]); if(tmp > rec[i].z)ans ++;//符合要求结果加一 for(int j = rec[i].y;j <= n;j += j & -j)h[j] = max(h[j],rec[i].z); } cout<<ans<<endl; return 0; }