【BZOJ2827】千山鸟飞绝 离散化+splay

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/45721413");
}

题解:

首先先把坐标离散化一下,
然后对于每个坐标点我们建一棵平衡树,每次插入操作后给整颗平衡树下传一下需求的两个标记。

注意:

splay有的人(比如我)习惯每棵都先建-inf、inf两个节点以便于查找前驱后继。然后这道题的数据是爆0x3f3f3f3f的……呵呵,怪不得我跑了千组极限数据都没挂,然后vfk的数据我直接爆零……(我的点权值随机的[1,10086])

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 35000
#define M 700000
#define ls son[x][0]
#define rs son[x][1]
#define end(i) n+(i<<1)
#define is(x) (son[fa[x]][1]==x)
#define inf 0x7fffffff
using namespace std;
int ad[M],ap[M]; // 团结值、士气值
struct DATA
{
    int v,f,k; // 第v只鸟于时刻f飞到k处。
    long long x,y;
    void read(int _f){f=_f;scanf("%d%lld%lld",&v,&x,&y);}
}gank[M];
bool cmpf(const DATA &A,const DATA &B){return A.f<B.f;}
bool cmpxy(const DATA &A,const DATA &B){return A.x==B.x?A.y<B.y:A.x<B.x;}
int n,m,cnt;
struct SPT
{
    int root[M],belong[M];
    int son[M][2],fa[M],kda[M]; // 威武值

    int AD[M],AP[M],num[M];

    void pushdown(int x)
    {
        ad[x]=max(ad[x],AD[x]);
        ap[x]=max(ap[x],AP[x]);
        AD[ls]=max(AD[ls],AD[x]);
        AD[rs]=max(AD[rs],AD[x]);
        AP[ls]=max(AP[ls],AP[x]);
        AP[rs]=max(AP[rs],AP[x]);
        AD[x]=AP[x]=0;
    }
    void link(int x,int y,int d){son[y][d]=x,fa[x]=y;}
    void rotate(int x)
    {
        int y,z,i=is(x),t;
        y=fa[x],z=fa[y],t=son[x][!i];
        pushdown(y),pushdown(x);
        link(x,z,is(y)),link(y,x,!i),link(t,y,i);
        son[0][0]=son[0][1]=fa[0]=0;
    }
    void splay(int rt,int x,int d=0)
    {
        int y,z;
        while(fa[x]!=d)
        {
            y=fa[x],z=fa[y];
            if(z==d)rotate(x);
            else rotate(is(x)==is(y)?y:x),rotate(x);
        }
        if(!d)root[rt]=x;
    }
    int pred(int rt,int x)
    {
        splay(rt,x);
        for(x=ls;rs;x=rs);
        return x;
    }
    void insert(int rt,int v)
    {
        belong[v]=rt;
        int x=root[rt],pre,pr;pushdown(x);
        while(son[x][kda[x]<kda[v]])
            pushdown(x=son[x][kda[x]<kda[v]]);
        link(v,x,kda[x]<kda[v]),num[rt]++;
        splay(rt,v);
        pre=pred(rt,end(rt));
        pr=pred(rt,pre);
        if(pre<=n)
        {
            pushdown(pre);
            AD[pre]=num[rt]-1;
            ap[pre]=max(ap[pre],kda[pr]);
            int lss=son[pre][0],rss=son[pre][1];
            AP[lss]=max(AP[lss],kda[pre]);
            AP[rss]=max(AP[rss],kda[pre]);
        }
    }
    void remove(int rt,int x)
    {
        int pre=pred(rt,x);
        splay(rt,pre),splay(rt,x,pre);
        pushdown(pre),pushdown(x);
        link(rs,pre,1),num[rt]--;
        ls=rs=fa[x]=0;
    }
    void init(int m)
    {
        int a,b;
        for(int i=1;i<=m;i++)
        {
            b=end(i),a=b-1;
            root[i]=a,kda[a]=-inf;
            link(b,a,1),kda[b]=inf;
        }
        for(int i=1;i<=n;i++)insert(gank[i].k,gank[i].v);
    }
    void work(int i)
    {
        remove(belong[gank[i].v],gank[i].v);
        insert(gank[i].k,gank[i].v);
    }
}spt;
int main()
{
    int i,j,k;
    int a,b,c;

    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        gank[i].read(0);
        spt.kda[i]=gank[i].v;
        gank[i].v=i;
    }
    scanf("%d",&m);
    for(i=1;i<=m;i++)gank[i+n].read(i);
    sort(gank+1,gank+n+m+1,cmpxy);
    gank[0].x=gank[1].x^1;
    for(i=1;i<=n+m;i++)
    {
        if(gank[i].x!=gank[i-1].x||gank[i].y!=gank[i-1].y)cnt++;
        gank[i].k=cnt;
    }
    sort(gank+1,gank+n+m+1,cmpf);
    spt.init(cnt);
    for(i=n+1;i<=n+m;i++)
        spt.work(i);
    for(i=1;i<=n;i++)spt.remove(spt.belong[i],i);
    for(i=1;i<=n;i++)printf("%lld\n",(long long)ad[i]*ap[i]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值