【GDOI2018模拟7.14】小奇的糖果 树状数组+扫描线

来源:互联网 发布:适合学生的网络兼职 编辑:程序博客网 时间:2024/05/09 19:04

好像上去讲的有点快,主要是本身就挺短,,这里讲的会详细一点。
题意很明显就不说了。

题意就不说了,注意线段上的点是不能选的。
首先要明确一个东西,这里说是双向链表维护,是因为我们维护了一个点的前驱后继,这符合双向链表的定义,但是实际上大家把他当作普通数组一样维护就好了。

先把横坐标离散化,注意是线性离散的话初值不能是0因为有的坐标可以是0(因为这个所以WA0了)。
首先我们假设我们画的那一条直线在无限低的地方,这时候答案相当于相邻两个同种颜色的中间的最大点数。(注意不包括这种颜色)
怎么求?
把横坐标从小到大排序,维护l[i],r[i]分别表示距离i最近的相同颜色的点的编号。
直接维护比较麻烦,设一个last[i]表示i这种颜色最近一次出现的地方在哪个位置,然后用last维护l,r。
维护的同时维护答案,用树状数组和l,r维护一下区间和就好了。

当然,这是满状态,也就是直线在最下方的时候,然后我们将点按照纵坐标排序,逐渐向上移动,每一次将同一行的点从树状数组删掉,然后将l,r合并。同时维护答案,跟上面的一样,用已经合并了的l,r更新一下就好了。

最后还有一种情况就是枚举一下哪一种颜色不选,然后对ans取个max,注意要在删点之前,也是用树状数组维护。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e5+5;int n,k,ans;struct point{    int x,y,id,col;}po[N];int a[N],pos[N],val[N],last[N],Left[N],Right[N];//int f[2][N][N];inline int lowbit(int x){    return x&(-x);}inline void add(int x,int v){    while (x<=n+1)    {        val[x]+=v;        x+=lowbit(x);    }}inline int ask(int x){    int ret=0;    while (x>0)    {        ret+=val[x];        x-=lowbit(x);    }    return ret;}bool cmp1(point a,point b){    return a.x<b.x;}bool cmp2(point a,point b){    return a.y<b.y;}inline void solve(){    memset(val,0,sizeof(val));    memset(last,0,sizeof(last));    sort(po+1,po+1+n,cmp1);    pos[n+1]=n+1;    fo(i,1,n)add(po[i].x,1);    fo(i,1,n)    {        int l=last[po[i].col];        Left[po[i].id]=l,Right[po[i].id]=n+1;        last[po[i].col]=po[i].id;        if (l)Right[l]=po[i].id;        if (pos[l]+1<=pos[po[i].id]-1)ans=max(ans,ask(pos[po[i].id]-1)-ask(pos[l]));    }    fo(i,1,k)if (pos[last[i]]+1<=n)ans=max(ans,ask(n+1)-ask(pos[last[i]]));    sort(po+1,po+1+n,cmp2);    int j=1;    fo(i,1,n)    {        while (j<=n&&po[i].y==po[j].y)add(po[j].x,-1),j++;        Left[Right[po[i].id]]=Left[po[i].id];        Right[Left[po[i].id]]=Right[po[i].id];        if (pos[Right[po[i].id]]-1>=pos[Left[po[i].id]]+1)            ans=max(ans,ask(pos[Right[po[i].id]]-1)-ask(pos[Left[po[i].id]]));    }}int main(){    int cas=0;    scanf("%d",&cas);    while (cas--)    {        scanf("%d%d",&n,&k);        fo(i,1,n)        {            scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].col);            a[i]=po[i].x;            po[i].id=i;            //fo(j,1,n)            //f[0][i][j]=abs(po[i].x-po[j].x),f[1][i][j]=abs(po[i].y-po[j].y);        }        sort(a+1,a+1+n);        int tot=0;        ans=0;        fo(i,1,n)        po[i].x=pos[i]=lower_bound(a+1,a+1+n,po[i].x)-a;        solve();        fo(i,1,n)po[i].y=-po[i].y;        solve();        printf("%d\n",ans);    }}
阅读全文
0 0
原创粉丝点击