【BZOJ】3262: 陌上花开
3262: 陌上花开
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 4031 Solved: 1902
[Submit][Status][Discuss]
Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花A比另一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,Ma>=Mb。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
Output
包含N行,分别表示评级为0...N-1的每级花的数量。
Sample Input
10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
Sample Output
3
1
3
0
1
0
1
0
0
1
1
3
0
1
0
1
0
0
1
HINT
Source
三维偏序模板题。套路:第一维排序,第二维cdq,第三维树状数组。cdq的具体方法类似于归并排序,将左区间和右区间递归处理。把左右区间按第二维排序,双指针扫描,当右区间i一定时,在左边扫j,当第二维还满足条件时,在值域树状数组上找到j第三维的值,加上相同类型j的个数。当第二维j超过i时,在树状数组上查询小于等于i第三维的j的个数,更新答案。最后一定要把树状数组还原。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n, k, num[200005]; struct node { int a, b, c, w, ans; } qwq[100005], qaq[100005]; bool cmp1 ( node a, node b ) { if ( a.a == b.a ) { if ( a.b == b.b ) return a.c < b.c; return a.b < b.b; } return a.a < b.a; } bool cmp2 ( node a, node b ) { if ( a.b == b.b ) return a.c < b.c; return a.b < b.b; } int lowbit ( int x ) { return x & -x; } int pre[200005]; void add ( int x, int d ) { for ( int i = x; i <= k; i += lowbit ( i ) ) pre[i] += d; } int query ( int x ) { int ans = 0; for ( int i = x; i; i -= lowbit ( i ) ) ans += pre[i]; return ans; } void CDQ ( int l, int r ) { if ( l == r ) return ; int mid = ( l + r ) >> 1; CDQ ( l, mid ); CDQ ( mid + 1, r ); int i = mid + 1, j = l; sort ( qaq + l, qaq + mid + 1, cmp2 ); sort ( qaq + mid + 1, qaq + r + 1, cmp2 ); for ( ; i <= r; i ++ ) { while ( qaq[j].b <= qaq[i].b && j <= mid ) { add ( qaq[j].c, qaq[j].w ); j ++; } qaq[i].ans += query ( qaq[i].c ); } for ( i = l; i < j; i ++ ) add ( qaq[i].c, -qaq[i].w ); } int main ( ) { //freopen ( "testdata.in", "r", stdin ); //freopen ( "a.out", "w", stdout ); scanf ( "%d%d", &n, &k ); for ( int i = 1; i <= n; i ++ ) scanf ( "%d%d%d", &qwq[i].a, &qwq[i].b, &qwq[i].c ); sort ( qwq + 1, qwq + 1 + n, cmp1 ); int cnt = 0, sum = 0; for ( int i = 1; i <= n; i ++ ) { cnt ++; if ( qwq[i].a != qwq[i+1].a || qwq[i].b != qwq[i+1].b || qwq[i].c != qwq[i+1].c ) { qaq[++sum] = qwq[i]; qaq[sum].w = cnt; cnt = 0; } } CDQ ( 1, sum ); for ( int i = 1; i <= sum; i ++ ) num[qaq[i].ans + qaq[i].w - 1] += qaq[i].w; for ( int i = 0; i < n; i ++ ) printf ( "%d\n", num[i] ); return 0; }
【8.21更新】CDQ里面用sort很慢啊qwq,直接开个辅助数组归并比较优秀。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n, k, tot; int ans[100005]; struct node { int a, b, c, sum, ans; } init[100005], flower[100005]; bool cmp ( node a, node b ) { if ( a.a == b.a ) { if ( a.b == b.b ) return a.c < b.c; return a.b < b.b; } return a.a < b.a; } int lowbit ( int x ) { return x & -x; } int pre[200005]; void add ( int pos, int d ) { for ( int i = pos; i <= k; i += lowbit ( i ) ) pre[i] += d; } int query ( int pos ) { int ans = 0; for ( int i = pos; i; i -= lowbit ( i ) ) ans += pre[i]; return ans; } node fz[100005]; void CDQ ( int L, int R ) { if ( L == R ) return ; int mid = ( L + R ) >> 1; int qwq = 0; CDQ ( L, mid ); CDQ ( mid + 1, R ); int i = L, j = mid + 1; while ( i <= mid && j <= R ) { if ( flower[i].b <= flower[j].b ) { add ( flower[i].c, flower[i].sum ); fz[++qwq] = flower[i++]; } else { flower[j].ans += query ( flower[j].c ); fz[++qwq] = flower[j++]; } } for ( ; j <= R; j ++ ) { flower[j].ans += query ( flower[j].c ); fz[++qwq] = flower[j]; } for ( ; i <= mid; i ++ ) { fz[++qwq] = flower[i]; add ( flower[i].c, flower[i].sum ); } for ( int i = L; i <= mid; i ++ ) add ( flower[i].c, -flower[i].sum ); int o = 0; for ( i = L; i <= R; i ++ ) flower[i] = fz[++o]; } int main ( ) { scanf ( "%d%d", &tot, &k ); for ( int i = 1; i <= tot; i ++ ) scanf ( "%d%d%d", &init[i].a, &init[i].b, &init[i].c ); int cnt = 0; sort ( init + 1, init + 1 + tot, cmp ); for ( int i = 1; i <= tot; i ++ ) { cnt ++; if ( init[i].a != init[i+1].a || init[i].b != init[i+1].b || init[i].c != init[i+1].c ) { flower[++n] = init[i]; flower[n].sum = cnt; cnt = 0; } } CDQ ( 1, n ); for ( int i = 1; i <= n; i ++ ) ans[flower[i].ans+flower[i].sum-1] += flower[i].sum; for ( int i = 0; i < tot; i ++ ) printf ( "%d\n", ans[i] ); return 0; }