bzoj3262陌上花开 (CDQ,BIT)

题目大意
bzoj

给定n朵花,每个花有三个属性,定义 f [ i ] 为满足 a j a i b j b i c j c i 的j的数量,
d [ 0 , n ) , f [ i ] = d 的数量

这题是一道CDQ的入门题

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

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

对于这个题,有三维,首先对于第一维进行排序去重,然后进行CDQ,递归到一层,分别对 [ l , m i d ] [ m i d + 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 ] . c n t 1 ,是因为要统计 而不是 <

上总的代码

#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;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/80400449