Gym 101147F Bishops Alliance 题解

题意
给定一个棋盘若干棋子,问最多可以找出多少棋子符合下列条件,在一条对角线上且它们中的任意两个沿对角线上路径的格数不小于 p2i+p2j+C
思路
首先很轻易地能推出这个式子的传递性,所以我们只需要对一条对角线从上往下放棋子,不断地看对于要放的这个棋子,最后一个可以跟它符合条件的棋子是哪个,会形成一条多长的链。将式子简单移项得 jp2jp2i+i+C1 ,所以每次找到符合条件的最后一项,再找到前缀里最大的值,加1并更新最大值,用树状数组维护
代码
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
long long T,n,m,C;
typedef struct bishop
{
    long long r;
    long long c;
    long long p;
    long long id;
}bishop;
bool cmp1(bishop a,bishop b)
{
    return a.r<b.r;
}
bool cmp2(bishop a,bishop b)
{
    if(a.p*a.p+a.r+C-1!=b.p*b.p+b.r+C-1)
        return a.p*a.p+a.r+C-1<b.p*b.p+b.r+C-1;
    else return a.r<b.r;
}
vector<bishop> v[400001];
long long hsh[100001],BIT[100001];
long long e;
long long lowbit(long long x)
{
    return x&(-x);
}
void change(long long x,long long d)
{
    while(x<=e)
    {
        BIT[x]=max(BIT[x],d);
        x+=lowbit(x);
    }
}
long long qmax(long long x)
{
    long long ret=0;
    while(x>0)
    {
        ret=max(ret,BIT[x]);
        x-=lowbit(x);
    }
    return ret;
}
long long binarysearch(long long l,long long r,long long x)
{
    long long mid=(l+r)/2;
    if(l==r)
        return l;
    if(r-l==1)
    {
        if(hsh[r]<=x)
            return r;
        return l;
    }
    if(hsh[mid]>x)
        return binarysearch(l,mid-1,x);
    else return binarysearch(mid,r,x);
}
int main()
{
    freopen("bishops.in","r",stdin);
    bishop temp;
    long long p,ans,anss;
    scanf("%I64d",&T);
    while(T--)
    {
        ans=0;
        scanf("%I64d%I64d%I64d",&n,&m,&C);
        for(long long i=0;i<m;i++)
        {
            scanf("%I64d%I64d%I64d",&temp.r,&temp.c,&temp.p);
            v[temp.r+temp.c].push_back(temp);
            v[temp.r-temp.c+3*n].push_back(temp);
        }
        for(long long i=0;i<4*n;i++)
        {
            e=v[i].size();
            sort(v[i].begin(),v[i].end(),cmp2);
            for(long long j=0;j<v[i].size();j++)
            {
                v[i][j].id=j+1;
                hsh[j+1]=v[i][j].p*v[i][j].p+v[i][j].r+C-1;
            }
            sort(v[i].begin(),v[i].end(),cmp1);
            for(long long j=0;j<v[i].size();j++)
            {
                p=binarysearch(0,v[i].size(),v[i][j].r-v[i][j].p*v[i][j].p);
                change(v[i][j].id,qmax(p)+1);
            }
            anss=qmax(v[i].size());
            if(anss>ans)
                ans=anss;
            /*printf("%I64d: ",i);
            for(long long j=1;j<=v[i].size();j++)
                printf("%I64d ",BIT[j]);
            printf("\n");*/
            for(long long j=1;j<=v[i].size();j++)
                BIT[j]=0;
        }
        printf("%I64d\n",ans);
        for(long long i=0;i<4*n;i++)
            v[i].clear();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值