树套树【bzoj3262】陌上花开

/*

【bzoj3262】陌上花开

2014年6月19日1,2430

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的每级花的数量。*/

//树套树  cdq分治不会

//卡时函数大视野竟然不认,给我报了n遍RE,气死我了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define M 5000005
using namespace std;
struct shu
{
 int x,y,z;
}a[100005];
int n,m,sum[100005],ans[100005],sz,root[200005],w[M],v[M],sz1[M],lr[M],rr[M],rou[M];
int tmp;
bool cmp(shu a1,shu a2)
{
 if(a1.x==a2.x&&a1.y==a2.y)
   return a1.z<a2.z;
 if(a1.x==a2.x)
   return a1.y<a2.y;
 return a1.x<a2.x;
}
void update(int a1)
{
 sz1[a1]=sz1[lr[a1]]+sz1[rr[a1]]+w[a1];
}
void zuo(int &a1)
{
 int t=lr[a1];
 lr[a1]=rr[t];
 rr[t]=a1;
 update(a1);
 update(t);
 a1=t;
}
void you(int &a1)
{
 int t=rr[a1];
 rr[a1]=lr[t];
 lr[t]=a1;
 update(a1);
 update(t);
 a1=t;
}
void jiaa(int &a1,int a2)
{
 if(a1==0)
   {
    sz++;
    a1=sz;
    v[a1]=a2;
    sz1[a1]=1;
    w[a1]=1;
    rou[a1]=rand();
    return;
   } 
 sz1[a1]++;
 if(v[a1]==a2)
   {
    w[a1]++;
    return;
   }
 if(v[a1]>a2)
   {
    jiaa(lr[a1],a2);
    if(rou[lr[a1]]<rou[a1])
      zuo(a1);
   }
 else
   {
    jiaa(rr[a1],a2);
    if(rou[rr[a1]]<rou[a1])
      you(a1);
   }
}
void jia(int a1,int a2)
{
 for(;a1<=m;a1+=(a1&(-a1)))
   jiaa(root[a1],a2);
}
void askk(int a1,int a2)
{
 if(a1==0)
   return;
 if(v[a1]==a2)
    {
     tmp+=w[a1]+sz1[lr[a1]];
     return;
    }
 if(v[a1]>a2)
   askk(lr[a1],a2);
 else
   {
    tmp+=w[a1]+sz1[lr[a1]];
    askk(rr[a1],a2);
   }
 return;
}
void ask(int a1,int a2)
{
 for(;a1;a1-=(a1&(-a1)))
   askk(root[a1],a2);
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=n;i++)
   scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
 sort(a+1,a+n+1,cmp);
 for(int i=1;i<=n;i++)
  {
   if(a[i].y==a[i+1].y&&a[i].z==a[i+1].z&&a[i].x==a[i+1].x&&i!=n)
     sum[i+1]+=sum[i]+1;
   else
     {
      tmp=0;
      ask(a[i].y,a[i].z);
      ans[tmp]+=sum[i]+1;
  }
   jia(a[i].y,a[i].z);
     }
 for(int i=0;i<n;i++)
   printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-08-12 10:09:17

树套树【bzoj3262】陌上花开的相关文章

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

树套树乱讲

树套树乱讲 树状数组套线段树 先学会主席树. 主席树可以被理解为一个二维平面,其中n棵树可以视作横轴,每棵树中的坐标范围(也就是线段树的坐标范围)可以视作纵轴.这样一来就是用主席树维护了一些在二维平面上的点,给定\(a,b,c,d\),可以在\(O(\log{n})\)的时间内求出满足\(a\le x_i\le b,c\le y_i\le d\)的\(i\)的数量. 而树状数组套线段树就是把这个问题动态化. 对于上述的问题,我们是通过对主席树直接维护前缀和,查询时两棵主席树相减,再在区间\([c

树套树乱讲的代码

树套树乱讲的代码 由于部分代码的完成时间较早所以码风可能有些差异,敬请谅解. 动态区间Kth 题面 整体二分题解 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int N=10005; struct segment_tree{int v;int ls,rs;}t

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

HDU HDOJ5412(树套树

题目:要求支持带修改维护区间第k大的值.所谓的动态区间第k大. 思路:题解说的是树状数组套treap,然而没想通树状数组怎么维护...线段树的话就是把所有的值离散化一下,离线建个关于值的线段树,每个节点是一个treap,treap里的值用位置做关键字,然后做区间查询,复杂度是O(nlogn*logn).基本也是经典的树套树做法....然后赛后写了两遍都没过.....今天心血来潮再挑战一下,结果从8点调到晚上1点.其间各种爆内存各种re各种t.....随机数据对拍了好久没拍出问题来....然后一直