• 三维偏序——cdq分治


    题目:

      有 n 个元素,第 i 个元素有 ai 、bi 、ci 三个属性,设 f(i) 表示满足 aj ≤ ai 且 bj ≤ bi 且 cj ≤ ci 的 j 的数量。对于 d∈[0,n),求 f(i)=d  的 i 的数量。

    题解:

      可以对第一维a进行排序(O(nlogn)),然后对第二维进行归并排序(O(nlogn)),在归并时对于 b<= bj可以将对应的 c的个数加进树状数组(O(nlogk)),在bi b时统计小于cj的数量,最后回溯的时候不要忘了清空树状数组。对于重复的数,可以先进行去重,详见代码。

    p3810AC代码:

      1 #include <bits/stdc++.h>
      2 #define numm ch-48
      3 #define pn putchar('
    ')
      4 #define pd putchar(' ')
      5 #define debug(args...) cout<<#args<<"->"<<args<<endl
      6 //#define bug cout<<"*******************"<<endl
      7 using namespace std;
      8 template<typename T>
      9 void read(T &res) {
     10     char ch;bool flag=false;
     11     while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
     12     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
     13     flag&&(res=-res);
     14 }
     15 template<typename T>
     16 void write(T x) {
     17     if(x<0) x=-x,putchar('-');
     18     if(x>9) write(x/10);
     19     putchar(x%10+48);
     20 }
     21 typedef long long ll;
     22 const int maxn=100000+10;
     23 const int inf=0x3f3f3f3f;
     24 struct node {
     25     int a,b,c;      ///a,b,c三个变量
     26     int ans,cnt;
     27     bool operator<(const node &x) const{
     28         if(a!=x.a) return a<x.a;
     29         else if(b!=x.b) return b<x.b;
     30         else if(c!=x.c) return c<x.c;
     31     }
     32 }e[maxn],temp[maxn];///temp[]:存放归并后的数
     33 int tree[maxn<<1],k,res[maxn];  ///tree[]:树状数组
     34 int lowbits(int x) {
     35     return x&-x;
     36 }
     37 void add(int i,int v) {
     38     while(i<=k) {
     39         tree[i]+=v;
     40         i+=lowbits(i);
     41     }
     42 }
     43 int query(int i) {
     44     int ans=0;
     45     while(i) {
     46         ans+=tree[i];
     47         i-=lowbits(i);
     48     }
     49     return ans;
     50 }
     51 void cdq(int l,int r) {
     52     if(l==r) {
     53         e[l].ans+=e[l].cnt-1;  ///不要把自己算进去,-1
     54         return ;
     55     }
     56     int mid=l+r>>1;
     57     cdq(l,mid);
     58     cdq(mid+1,r);
     59     int i=l,j=mid+1,op=l;///双指针进行归并
     60     while(j<=r) {   ///把右边大于左边的都统计一次
     61         while(i<=mid&&e[i].b<=e[j].b) {
     62             add(e[i].c,e[i].cnt);   ///把个数加到对应的权值之上
     63             temp[op++]=e[i];
     64             i++;
     65         }
     66         e[j].ans+=query(e[j].c);
     67         temp[op++]=e[j];
     68         j++;
     69     }
     70     for(int j=l;j<i;j++)    ///清空树状数组
     71         add(e[j].c,-e[j].cnt);
     72     while(i<=mid)   ///左边(i那部分)有可能没算完
     73         temp[op++]=e[i],i++;
     74 
     75     for(i=l;i<=r;i++)///把排序后的temp赋值给e
     76         e[i]=temp[i];
     77 }
     78 int main()
     79 {
     80     int n;
     81     read(n);read(k);///k:a,b,c的大小上限
     82     for(int i=1;i<=n;i++)
     83         read(e[i].a),read(e[i].b),read(e[i].c);
     84     sort(e+1,e+1+n);
     85     int cnt=1,tot=0;
     86     for(int i=2;i<=n;i++) { ///去重
     87         if(e[i-1].a^e[i].a||e[i-1].b^e[i].b||e[i-1].c^e[i].c) {
     88             e[++tot]=e[i-1];
     89             e[tot].cnt=cnt;
     90             e[tot].ans=0;
     91             cnt=1;
     92         }
     93         else cnt++;
     94     }
     95     e[++tot]=e[n];
     96     e[tot].cnt=cnt;
     97     e[tot].ans=0;
     98     cdq(1,tot);
     99     for(int i=1;i<=tot;i++)
    100         res[e[i].ans]+=e[i].cnt;///最后的答案为ans的数有多少个,所以加上cnt
    101     for(int i=0;i<n;i++)
    102         write(res[i]),pn;
    103     return 0;
    104 }
    View Code
  • 相关阅读:
    Java动态绑定与多态
    Java中的equals,==,compareTo和compare的比较
    Java访问控制权限
    如何用eclipse进行jar文件打包?
    堆和栈的区别
    Java命名规则
    Java面向对象的基本概念
    java中length,length(),size()区别
    《剑指offer》第二十题:表示数值的字符串
    《剑指offer》第十九题:正则表达式匹配
  • 原文地址:https://www.cnblogs.com/wuliking/p/11747524.html
Copyright © 2020-2023  润新知