hdu 4742 Pinball Game 3D(三维LIS&cdq分治&BIT维护最值)

Pinball Game 3D

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 688    Accepted Submission(s): 276

Problem Description

RD is a smart boy and excel in pinball game. However, playing common 2D pinball game for a great number of times results in accumulating tedium.

Recently, RD has found a new type of pinball game, a 3D pinball game. The 3D pinball game space can be regarded as a three dimensional coordinate system containing N balls. A ball can be considered as a point. At the beginning, RD made a shot and hit a ball.
The ball hit by RD will move and may hit another ball and the “another ball” may move and hit another another ball, etc. But once a ball hit another ball, it will disappear.

RD is skilled in this kind of game, so he is able to control every ball‘s moving direction. But there is a limitation: if ball A‘s coordinate is (x1,y1,z1) and ball B‘s coordinate is (x2,y2,z2), then A can hit B only if x1 <= x2 and y1 <= y2 and z1 <= z2.

Now, you should help RD to calculate the maximum number of balls that can be hit and the number of different shooting schemes that can achieve that number. Two schemes are different if the sets of hit balls are not the same. The order doesn‘t matter.

Input

The first line contains one integer T indicating the number of cases.

In each case, the first line contains one integer N indicating the number of balls.

The next N lines each contains three non-negative integer (x, y, z), indicating the coordinate of a ball.

The data satisfies T <= 3, N <= 105, 0 <= x, y, z <= 230, no two balls have the same coordinate in one case.

Output

Print two integers for each case in a line, indicating the maximum number of balls that can be hit and the number of different shooting schemes. As the number of schemes can be quite large, you should output this number mod 230.

Sample Input

2
3
2 0 0
0 1 0
0 1 1
5
3 0 0
0 1 0
0 0 1
0 2 2
3 3 3

Sample Output

2 1
3 2

Hint

In the first case, RD can shoot the second ball at first and hit the third ball indirectly.
In the second case, RD can shoot the second or the third ball initially and hit the fourth ball as well as the fifth ball. Two schemes are both the best.

Source

2013 ACM/ICPC Asia Regional Hangzhou Online

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  5061 5059 5058 5053 5052

题意:

就是给你n(1e5)个三元组、然后要你求这n个三元组的LIS。和这样LIS的方案数。一个三元祖a比另一个元祖b大的条件是ax>=bx,ay>=by,az>=bz。

思路:

如果是一维的就很好做。排个序就完了。两维的话。对x排序。然后dp[i]表示以i结尾最长序列长度.dp[i]=max(dp[i],dp[j]+1)。j<i&&y[j]<y[i]。三维的话就要用到分治的思想了。我们先按x排序x一样按y排。y一样再按x排。这样就能保证dp[i]一定是由1~i-1转移来的。然后我们就可以分治了。比如我们要算[l,r]的dp值。mid=(L+r)/2假设我们已经算出了[l,mid]的dp值。我们是不是可以用[l,mid]的dp值去更新[mid+1,r]的dp值。因为dp[i]一定是由1~i-1转移来的所以我们可以建一个树状数组维护z值为zz的最大dp(由于这题每次都是查询[1,x]整个区间所以可以用树状数组来维护最值)。当然z值是离散化后的值。然后我们两边的y排序.然后对于[mid+1,r]的每一个dp我们按y值从小到大更新。先把[l,mid]中y值比自己小的插到树状数组中。然后查询数组数组中z小于自己z的最大dp就行了。这样就可以保证树状数组中的元素x,y都是合理的然后查询的z也是合理的。然后递归处理就行了。先solve(l,mid)然后更新[mid+1,r]再solve(mid+1,r)。当然递归的时候也可以顺便进行一些排序操作(归并排序)以提高效率。

详细见代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
const int mod=1<<30;
typedef long long ll;
struct node
{
    int x,y,z;
    inline bool operator <(const node& tt) const
    {
        if(x!=tt.x)
            return x<tt.x;
        if(y!=tt.y)
            return y<tt.y;
        return z<tt.z;
    }
} po[maxn];
int dp[maxn],sy[maxn],sz[maxn],mv[maxn],ans;
int tmp[maxn<<1],ty[maxn],ptr;
ll num[maxn],nv[maxn],ansn;
bool cmp(int a,int b)//注意y必须这么排.不然可能出现y相等的时候i+1排到i前面的情况.
{
    if(po[a].y!=po[b].y)
        return po[a].y<po[b].y;
    return a<b;
}
void update(int x,int v,ll d,int mn)
{
    for(int i=x;i<=mn;i+=i&-i)
    {
        if(v>mv[i])
            mv[i]=v,nv[i]=d;
        else if(v==mv[i])
            nv[i]+=d;
    }
}
int qu(int x,ll &nn)
{
    int ret=0;
    for(int i=x;i>0;i-=i&-i)
    {
        if(ret<mv[i])
            ret=mv[i],nn=nv[i];
        else if(mv[i]==ret)
            nn+=nv[i];
    }
    return ret;
}
void solve(int l,int r)
{
    if(l==r)
    {
        if(dp[l]>ans)
            ans=dp[l],ansn=num[l];
        else if(dp[l]==ans)
            ansn+=num[l];
        sz[l]=po[l].z;
        return;
    }
    int mid=(l+r)>>1,le=l,ri=mid+1,len=r-l+1,ml=mid-l+1,lim,h,i;
    memmove(tmp+ptr,sy+l,len*sizeof(int));
    for(i=0;i<len;i++)
        if(tmp[ptr+i]<=mid)//直接把排好的序划分下去就行了。
            sy[le++]=tmp[ptr+i];
        else
            sy[ri++]=tmp[ptr+i];
    ptr+=len;
    solve(l,mid);
    lim=ptr,ptr-=len;
    for(i=1;i<=ml;i++)
        mv[i]=0;
    for(i=ptr;i<lim;i++)
    {
        if(tmp[i]<=mid)
        {
            h=lower_bound(sz+l,sz+l+ml,po[tmp[i]].z)-(sz+l)+1;
            update(h,dp[tmp[i]],num[tmp[i]],ml);
            continue;
        }
        h=lower_bound(sz+l,sz+l+ml,po[tmp[i]].z)-(sz+l);
        if(h>=ml||sz[l+h]>po[tmp[i]].z)
            h--;
        if(h>=0)
        {
            ll cc=0;
            int tt=qu(h+1,cc)+1;
            if(tt>dp[tmp[i]])
                dp[tmp[i]]=tt,num[tmp[i]]=cc;
            else if(tt==dp[tmp[i]]&&tt!=1)
                num[tmp[i]]+=cc;
        }
    }
    solve(mid+1,r);
    merge(sz+l,sz+l+ml,sz+l+ml,sz+l+len,ty);
    memmove(sz+l,ty,len*sizeof(int));
}
int main()
{
    int t,n,i;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].z);
        ansn=ptr=ans=0;
        sort(po+1,po+n+1);
        for(i=1;i<=n;i++)
            sy[i]=i,dp[i]=1,num[i]=1;
        sort(sy+1,sy+n+1,cmp);
        solve(1,n);
        printf("%d %I64d\n",ans,ansn%mod);
    }
    return 0;
}
/*
送一组数据。网上好多代码都过不了这组。就是因为排序y的时候i+1排到i前面去了。导致少更新很多
杭电数据比较水就水过去了。
1
17
2 0 0
2 1 1
1 2 1
1 0 0
0 0 1
0 2 0
0 2 2
0 1 1
2 0 1
1 2 2
0 1 0
2 0 2
2 2 2
0 1 2
1 0 2
1 1 1
0 0 2
*/
时间: 2024-08-04 02:11:27

hdu 4742 Pinball Game 3D(三维LIS&cdq分治&BIT维护最值)的相关文章

hdu 4742 Pinball Game 3D(三维LIS&amp;amp;cdq分治&amp;amp;BIT维护最值)

Pinball Game 3D Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 688    Accepted Submission(s): 276 Problem Description RD is a smart boy and excel in pinball game. However, playing common 2D p

【CDQ】 HDU 4742 Pinball Game 3D

通道 题意:给你n(1e5)个三元组.然后要你求这n个三元组的LIS.和这样LIS的方案数.一个三元祖a比另一个元祖b大的条件是ax>=bx,ay>=by,az>=bz 思路:先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之后用树状数组维护就可以 代码: #include <cstdio> #include <cstring> #include <algorithm> using names

BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那么可以按照插入的时间顺序看作是一维x,插入的数在原本序列的下标是一维y,插入的数本身是一维z.那么问题可以转化成每插入一个数(xx,yy,zz),求有多少个数(x,y,z)使得 x < xx,y < yy,z > zz .一开始先对 x 进行排序,然后进行CDQ分治.这样可以干掉一维,保证随

bzoj 1176 Mokia(CDQ分治)

[题目链接]  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=96974 [题意] 定义查询操作与修改操作:1 x y z 为将格子(x,y)修改为z:2 x1 y1 x2 y2为查询以(x1,y1)为左上(x2,y2)为右下的子矩阵之和. [思路] cdq分治. 矩阵初始值都为s,所以先不考虑. 首先明确每一个修改操作都互不影响.然后把每一个对子矩阵的询问操作差分为对四个点的“前缀和”操作. 先把所有的操作按照x升序排列

HDU4742----Pinball Game 3D(三维LIS、CDQ分治)

题意:三维空间内 n个小球,对应坐标(x,y,z).输出LIS的长度以及方案数. 首先可以先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之后用树状数组维护就可以了. 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

UvaLive 6667 Longest Chain (分治求三维LIS)

题目大意: 题目给出了定义的小于号,然后求出一个LIS... 思路分析: 这道题目的是一个严格递增的,和 Hdu 4742 类似.只不过Hdu的这道题是一个不递减的序列. 简单说一下Hdu 4742的做法. 首先我们可以想到的是一维的LIS,那么简单就是n. 然后二维的LIS,就是先排序一维,然后用求第二维的LIS. 现在问题扩展到三维.依然排序一维. 假设我们排序的是z. 然后记下排序后的id.现在已知,id小的z就小. 然后开始分治,类似线段树的递归.对于一个区间,我们将这个区间的所有元素取

HDU 5324 Boring Class【cdq分治】

这就是一个三维排序的问题,一维递减,两维递增,这样的问题用裸的CDQ分治恰好能够解决. 如同HDU 4742(三维排序,一个三维都是递增的) 由于最小字典序比較麻烦,所以要从后面往前面做分治.每一个点的dp值表示以这个点为起点.最长能够延伸多长. 本来是想依照Li排序,可是这样做在cdq的时候实在是太难以处理了.所以就依照idx排序.也就是不须要排序. 然后依照Ri排序,对于左边,保证右边的每一个R值大于左边的值.并用树状数组维护Li(由于Li须要递减.所以树状数组恰好能够维护右边的Li小于左边

HDU 5126(stars)四维偏序,cdq分治

题意:给两种操作,进行5万次.操作一:加入一个三维序偶(a,b,c)到集合S里:第二种操作,给两个三维序偶(a1,b1,c1)和(a2,b2,c2),问当前S里有多少个序偶(a,b,c)满足a1<=a<=a2, b1<=b<=b2, c1<=c<=c2.题目保证了a1<=a2,b1<=b2,c1<=c2.所有数在[1,1e9]内 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5126 解法:将操作编号也加入到