bzoj3262陌上花开 (CDQ,BIT)

题目大意

给定n朵花,每个花有三个属性,定义\(f[i]\)为满足\(a_j \le a_i\)且\(b_j \le b_i\)且\(c_j \le c_i\)的j的数量,

求\(d \in [0,n)\),\(f[i]=d\)的数量

这题是一道CDQ的入门题

CDQ其实本质上是一个分治的过程,需要将询问离线,然后进行分治

一般都是:

if (l==r) return;
cdq(l,mid);
cdq(mid+1,r);
处理左半区间对右半区间的影响

对于这个题,有三维,首先对于第一维进行排序去重,然后进行CDQ,递归到一层,分别对\([l,mid]\)和\([mid+1,r]\)分别进行第二维的排序,然后用树状数组统计左边区间对右边区间影响(就是求满足\(b_i<b_j\)的顺序对个数)

具体实现就是两个指针,一个从l开始跳,一个从mid+1开始循环,因为要统计左半区间对右边的影响,所以二者的循环上界也是要有限制的

具体可以看一下代码

    int pos = l;
    for (int i=mid+1;i<=r;i++)
    {
        while (b[pos].b<=b[i].b && pos<=mid) modify(b[pos].c,b[pos].cnt),pos++;
        b[i].ans+=query(b[i].c);
    }
    for (int i=l;i<pos;i++) modify(b[i].c,-b[i].cnt);

最后统计的答案的时候注意:

for (int i=1;i<=tot;i++) ans[b[i].ans+b[i].cnt-1]+=b[i].cnt;

这里加\(b[i].cnt-1\),是因为要统计 \(\le\) 而不是 \(<\)

上总的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();while (!isdigit(ch)) {if (ch==‘-‘) f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}return x*f;
}

const int maxn = 2e5+1e2;

struct Node{
    int a,b,c,cnt,ans;
};
Node a[maxn];
Node b[maxn];
int ans[maxn];
int c[maxn];
int n,maxval;
int tot;
int lowbit(int x){return x&(-x);}
void modify(int x,int p){for (int i=x;i<=maxval;i+=lowbit(i)) c[i]+=p;}
int query(int x){int ans=0; for (int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans;}
bool cmp1(Node a,Node b)
{
    if (a.a==b.a){
        if (a.b==b.b) return a.c<b.c;else 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;
}
void cdq(int l,int r)
{
    if (l==r) return;
    int mid = (l+r) >> 1;
    cdq(l,mid);cdq(mid+1,r);
    sort(b+l,b+mid+1,cmp2);
    sort(b+mid+1,b+r+1,cmp2);
    int pos = l;
    for (int i=mid+1;i<=r;i++)
    {
        while (b[pos].b<=b[i].b && pos<=mid) modify(b[pos].c,b[pos].cnt),pos++;
        b[i].ans+=query(b[i].c);
    }
    for (int i=l;i<pos;i++) modify(b[i].c,-b[i].cnt);
}
int main()
{
  scanf("%d%d",&n,&maxval);
  for (int i=1;i<=n;i++) scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
  sort(a+1,a+1+n,cmp1);
  for (int i=1;i<=n;i++)
  {
    if (a[i].a==a[i-1].a && a[i].b==a[i-1].b && a[i].c==a[i-1].c) b[tot].cnt++;
    else b[++tot]=a[i],b[tot].cnt=1;
  }
  cdq(1,tot);
  for (int i=1;i<=tot;i++) ans[b[i].ans+b[i].cnt-1]+=b[i].cnt;
  for (int i=0;i<n;i++) printf("%d\n",ans[i]);
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10160717.html

时间: 2024-10-09 06:20:51

bzoj3262陌上花开 (CDQ,BIT)的相关文章

BZOJ3262陌上花开 CDQ分治_BIT+Treap

三个属性, 第一个属性用cdq分治处理, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准), 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和,

BZOJ3262/洛谷P3810 陌上花开 CDQ分治 三维偏序 树状数组

原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 落谷P3810 题意 有$n$个元素,第$i$个元素有$a_i$.$b_i$.$c_i$三个属性,设$f(i)$表示满足$a_j\leq a_i$且$b_j\leq b_i$且$c_j\leq c_i$的$j$的数量.对于$d\in [0,n)$,求$f(i)=d$的数量. $n\leq 100000,max\{a_i,b_i,c_i|i

cdq分治入门--BZOJ3262: 陌上花开

n<=100000个人,每个人三个属性Ai,Bi,Ci,一个人i的等级为Ai>=Aj,Bi>=Bj,Ci>=Cj的人数,求每个等级有多少人. 裸的三维偏序.按照常规思路,一维排序,一维归并,一维利用单调性或用树状数组维护,这里选择后者. 先按Ai排序,然后在分治过程中,solve(l,mid),solve(mid+1,r),然后考虑(l,mid)对(mid+1,r)答案的贡献,先把这两部分分别按B排序,然后两个指针一起扫,扫的过程中,把C的值作下标丢进树状数组,查询时相当于树状数组

BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

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行,每

BZOJ3262: 陌上花开

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3262 三维.排序搞掉一维.让题目变成两维,然后用树状数组+cdq分治. 每次把平分的两个数组进行排序,然后扫一遍,由于排过序所以如果对于(l,mid)里的i对(mid+1,r)里的j有贡献的话,那它对j+1也是有贡献的. 可以先分治下去再处理当前的(l,r),这样可以少掉赋值的操作.记得最后要去掉(l,l1-1)的贡献. 然后就是对于完全相同的点可以先并起来. #include<cstrin

bzoj 3262: 陌上花开 -- CDQ分治

3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MB Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,00

bzoj3262: 陌上花开 二维树状数组

众所周知三维偏序可以树套树或者cdq 然后我就写了二维离散化+二维树状数组 然后被cdq艹飞了(ToT) #include<cstdio> #include<algorithm> #define N 100005 #define J i+(i&-i) #define F lower_bound #define G upper_bound using namespace std; struct io_t{ operator int(){ int x; scanf("

bzoj3262: 陌上花开(树套树)

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define maxn 100005 7 #define maxm 200005 8 #define maxk 2000005 9 using namespace std; 10 11 int n,K,temp,tot,root[ma

BZOJ 3262: 陌上花开 cdq分治 树状数组

https://www.lydsy.com/JudgeOnline/problem.php?id=3262 cdq分治板子题,一维排序,一维分治(cdq里的队列),一维数据结构(树状数组). 学dp优化前来复习--以前好像写过这道题但是没写博客啊--在校oj上写的题都没怎么写博客,追悔莫及 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #