Longest Chain—— 三维LIS

Let us compare two triples a = (xa, ya, za) and b = (xb, yb, zb) by a partial order ≺ defined as
follows.
a ≺ b ⇐⇒ xa < xb and ya < yb and za < zb
Your mission is to find, in the given set of triples, the longest ascending series a1 ≺ a2 ≺ · · · ≺ ak.
Input
The input is a sequence of datasets, each specifying a set of triples formatted as follows.
m n A B
x1 y1 z1
x2 y2 z2
.
.
.
xm ym zm
Here, m, n, A and B in the first line, and all of xi
, yi and zi (i = 1, . . . , m) in the following lines
are non-negative integers.
Each dataset specifies a set of m + n triples. The triples p1 through pm are explicitly specified
in the dataset, the i-th triple pi being (xi
, yi
, zi). The remaining n triples are specified by
parameters A and B given to the following generator routine.
int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
int r() {
a = 36969 * (a & M) + (a >> 16);
b = 18000 * (b & M) + (b >> 16);
return (C & ((a << 16) + b)) % 1000000;
}
Repeated 3n calls of r() defined as above yield values of xm+1, ym+1, zm+1, xm+2, ym+2, zm+2,
…, xm+n, ym+n, and zm+n, in this order.
You can assume that 1 ≤ m + n ≤ 3 × 105
, 1 ≤ A, B ≤ 2
16, and 0 ≤ xk, yk, zk < 106
for
1 ≤ k ≤ m + n.
The input ends with a line containing four zeros. The total of m + n for all the datasets does
not exceed 2 × 106
.
18
Output
For each dataset, output the length of the longest ascending series of triples in the specified set.
If pi1 ≺ pi2 ≺ · · · ≺ pik
is the longest, the answer should be k.
Sample Input
6 0 1 1
0 0 0
0 2 2
1 1 1
2 0 2
2 2 0
2 2 2
5 0 1 1
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
10 0 1 1
3 0 0
2 1 0
2 0 1
1 2 0
1 1 1
1 0 2
0 3 0
0 2 1
0 1 2
0 0 3
0 10 1 1
0 0 0 0
Output for the Sample Input
3
5
1
3

题意:

给你n组三元组,m组三元组是通过一个公式自己算出来,一个三元组大于另一个的条件是其中所有的元素都大于另外一个的对应元素,问你最长的递增链的长度是多少。

题解:

对于这个问题,先序和后序都是不行的,因为右子树的左子树和左子树的右子树的信息就会缺失,所以只能用中序遍历,在处理根的时候将右子树也处理掉。怎么办呢?在处理第二维的时候我们可以直接sort,for的过程中如果这个点是原本在左边的,就放到树状数组里,如果是在右边的,就查询。这样子右子树的左子树就可以查询左子树的全部了。要注意的是排序和二维的一样,除了x是从小到大排用来消除影响之外,y和z都是要从大到小排的,否则在加入树状数组的时候会出现问题。在CDQ内部是y从小到大,z从大到小,举个例子y1=1,z1=2,y2=1,z2=3,如果不是按照z从大到小排序呢?就会查到第一个了。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
//#define ll long long
struct node
{
    int x,y,z,flag,id;
}p[N],tmp[N];
bool cmp1(node a,node b)
{
    if(a.x!=b.x)
        return a.x<b.x;
    if(a.y!=b.y)
        return a.y>b.y;
    return a.z>b.z;
}
bool cmp2(node a,node b)
{
    if(a.y!=b.y)
        return a.y<b.y;
    return a.z>b.z;
}
int a , b , C = ~(1<<31), M = (1<<16)-1,n,m;
int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}
int maxn;
int sum[1000005];
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int val)
{
    for(int i=x;i<1000005;i+=lowbit(i))
        sum[i]=max(sum[i],val);
}
void clear(int x)
{
    for(int i=x;i<1000005;i+=lowbit(i))
        sum[i]=0;
}
int query(int x)
{
    int ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans=max(ans,sum[i]);
    return ans;
}
int dp[N];
void CDQ(int l,int r)
{
    if(r==l)
        return ;
    int mid=l+r>>1;
    CDQ(l,mid);
    for(int i=l;i<=r;i++)
    {
        tmp[i]=p[i];
        tmp[i].flag=(i<=mid);
    }
    sort(tmp+l,tmp+r+1,cmp2);
    for(int i=l;i<=r;i++)
    {
        if(tmp[i].flag)
            add(tmp[i].z,dp[tmp[i].id]);
        else
            dp[tmp[i].id]=max(dp[tmp[i].id],query(tmp[i].z-1)+1);
    }
    for(int i=l;i<=r;i++)
        if(tmp[i].flag)
            clear(tmp[i].z);
    CDQ(mid+1,r);
}
//int x[N],y[N],z[N];
int main()
{
    int A,B;
    while(~scanf("%d%d%d%d",&m,&n,&A,&B))
    {
        if(!m&&!n&&!A&&!B)
            break;
        a=A,b=B;
        for(int i=1;i<=n;i++)
            p[i+m].x=r()+1,p[i+m].y=r()+1,p[i+m].z=r()+1;//x[i+m]=p[i+m].x,y[i+m]=p[i+m].y,z[i+m]=p[i+m].z;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
            p[i].x++,p[i].y++,p[i].z++;
            //x[i]=p[i].x,y[i]=p[i].y,z[i]=p[i].z;
        }
        sort(p+1,p+n+m+1,cmp1);
        /*sort(x+1,x+1+n+m),sort(y+1,y+1+n+m),sort(z+1,z+1+n+m);
        int allx=unique(x+1,x+1+n+m)-x-1;
        int ally=unique(y+1,y+1+n+m)-y-1;
        int allz=unique(z+1,z+1+n+m)-z-1;
        for(int i=1;i<=n+m;i++)
        {
            p[i].x=lower_bound(x+1,x+allx+1,p[i].x)-x;
            p[i].y=lower_bound(y+1,y+ally+1,p[i].y)-y;
            p[i].z=lower_bound(z+1,z+allz+1,p[i].z)-z;
        }*/
        int all=0;
        for(int i=1;i<=n+m;i++)
            if(p[i].x!=p[i+1].x||p[i].y!=p[i+1].y||p[i].z!=p[i+1].z)
                p[++all]=p[i],p[all].id=all,dp[all]=1;
        maxn=0;
        CDQ(1,all);
        for(int i=1;i<=all;i++)
            maxn=max(maxn,dp[i]);
        printf("%d\n",maxn);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值