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 pid=5052" target="_blank">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-11-06 07:07:32

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

hdu 4742 Pinball Game 3D(三维LIS&amp;cdq分治&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

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

三维偏序:CDQ分治

cdq分治是一种常用的降维手段,可以解决偏序问题. 题目 给定$n$个三元组$(x, y, z)$,给定一个$f(a)$,表示所有元素$b$(自己不算),它的$x,y,z$均小于等于$a$的对应$x,y,z$,求$[0, n)$中每种$f$值的个数. $n \leq 100000$ $x, y, z \leq 200000$ 简单模型 一维:仅有$x$:按$x$排序即可. 二维:有$(x, y)$,按先$x$后$y$顺序排序,然后将$y$值用树状数组统计. 三维偏序:cdq分治解法 思想:类似归

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 解法:将操作编号也加入到

二维LIS(CDQ分治)

题目描述 给定一个长度为N的序列S,S的每个元素pi是一个二元组(xi,yi),定义pi<pj当且仅当xi<xj并且yi<yj,求S的最长上升子序列长度 输入格式 第一行一个N,表示一共有N个元素 接下来有N行,每行包含两个正整数xi,yi 输出格式 输出一行一个整数,代表序列S的最长上升子序列的长度 一道很好的模板题 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 usin

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

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

hdu 3642 Get The Treasury (三维的扫描线)

题目大意: 给出N个立方体. 求一个三维空间中被包围三次的空间的体积之和. 思路分析: 发现Z的范围很小.那么我们可以枚举Z轴,然后对 x y做扫描线. 而且不用枚举所有的Z ,只需要将Z离散化之后枚举. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define maxn 2222 #define debug puts("fuck!&q