2827: 千山鸟飞绝 splay打标记

Description
话说有一天doyouloveme和vfleaking到山里玩。谁知doyouloveme刚刚进山,所有的鸟儿竟被他的神犇气场给惊得全部飞走了。vfleaking顿时膜拜不已。
这时鸟王用鸟语说道:“!@#$%……?”安抚了一下众鸟的情绪。鸟王生性好斗,作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去。
每只鸟都有一个编号,都有一个威武值。每秒钟鸟王都会发一个命令,编号为v的鸟飞到(x,y)去(坐标系原点是山顶,坐标单位为鸟爪)。鸟飞得很快,一秒之内就飞到了,可以看作是瞬间移动。如果编号为v的鸟和编号为u的鸟某一时刻处在同一位置,它们就会互相鼓励,增加各自的士气值和团结值。一只鸟的士气值等于此刻与它处在同一位置的鸟中的威武值的最大值,团结值等于此刻与它处在同一位置的鸟的只数。如果每一时刻都没有鸟与它处在同一位置,则士气值和团结值都为0。要注意自己不能鼓励自己,计算士气值和团结值时不能算上自己。
t秒钟后,doyouloveme目测出了现在每只鸟的战斗力,于是感叹了一句:“不妙,我们得走了。”
正所谓团结的鸟儿一个顶俩,所以doyouloveme这样描述战斗力:一只鸟战斗力值等于它在0到t秒中士气值的最大值与团结值的最大值的乘积。注意不是乘积的最大值,而是最大值的乘积。
vfleaking很想知道现在每只鸟的战斗力,但是他当然不会啦,于是他把这个任务交给了你来完成。

题解:

首先把坐标离散化,对每个坐标建一棵splay,以鸟的编号为关键字。然后要支持删除、插入、维护最大值,把一个新的点插入,它的答案就用那棵splay的最大值和大小来更新,然后用它自己的值来更新原来splay里的点,用打标记就行了。但是我遇到个问题,就是原来的标记有可能会传到新插入的点,我的解决方法是在插入点的时候把它的父亲到根的标记都下传,很慢,但我没想到更好的方法了……

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=30010;
const int Maxt=300010;
const int inf=2147483647;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
map<pa,int>h;int cnt=0;
int to(int x,int y)
{
    if(!h[make_pair(x,y)])h[make_pair(x,y)]=++cnt;
    return h[make_pair(x,y)];
}
int n,T;
struct bird{int w,x,y;}a[Maxn];
int tot=0;
int fa[Maxn+Maxt],son[Maxn+Maxt][2],root[Maxn+Maxt],size[Maxn+Maxt];
int mx[Maxn+Maxt],v[Maxn+Maxt],d[Maxn+Maxt],t1[Maxn+Maxt],t2[Maxn+Maxt];
int ans1[Maxn],ans2[Maxn];
int pos[Maxn];
void up(int x)
{
    if(!x)return;
    int lc=son[x][0],rc=son[x][1];
    size[x]=size[lc]+size[rc]+1;
    mx[x]=max(d[x],max(mx[lc],mx[rc]));
}
void down(int x)
{
    int lc=son[x][0],rc=son[x][1];
    if(t1[x])
    {
        if(lc)t1[lc]=max(t1[lc],t1[x]),ans1[v[lc]]=max(ans1[v[lc]],t1[x]);
        if(rc)t1[rc]=max(t1[rc],t1[x]),ans1[v[rc]]=max(ans1[v[rc]],t1[x]);
        t1[x]=0;
    }
    if(t2[x])
    {
        if(lc)t2[lc]=max(t2[lc],t2[x]),ans2[v[lc]]=max(ans2[v[lc]],t2[x]);
        if(rc)t2[rc]=max(t2[rc],t2[x]),ans2[v[rc]]=max(ans2[v[rc]],t2[x]);
        t2[x]=0;
    }
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],w=(son[y][0]==x);
    son[y][w^1]=son[x][w];if(son[x][w])fa[son[x][w]]=y;
    son[z][son[z][1]==y]=x;fa[x]=z;
    son[x][w]=y;fa[y]=x;
    up(y);up(x);
}
int sta[Maxn+Maxt];
void work(int o,int x)
{
    int top=0;
    while(x)sta[++top]=x,x=fa[x];
    while(top)down(sta[top--]);
}
void splay(int o,int x,int rt)
{
    work(o,x);
    while(fa[x]!=rt)
    {
        int y=fa[x],z=fa[y];
        if(z==rt)rotate(x);
        else rotate(((son[z][0]==y)==(son[y][0]==x))?y:x),rotate(x);
    }
    if(!rt)root[o]=x;
}
int Find(int o,int x)
{
    int now=root[o];
    while(v[now]!=x)
    {
        if(!son[now][x>v[now]])break;
        now=son[now][x>v[now]];
    }
    return now;
}
void add(int o,int x,int y,int f)
{
    int t=++tot;
    v[t]=x;d[t]=mx[t]=y;fa[t]=f;size[t]=1;
    if(!f)return;
    work(o,f);
    son[f][x>v[f]]=t;
    up(f);splay(o,f,0);
}
void ins(int o,int x,int y)
{
    if(!root[o]){root[o]=tot+1;add(o,x,y,0);return;}
    add(o,x,y,Find(o,x));
}
void Insert(int o,int x,int y)
{
    int t=root[o];
    if(!t){ins(o,x,y);return;}
    ans1[x]=max(ans1[x],mx[t]);
    ans2[x]=max(ans2[x],size[t]);
    ins(o,x,y);
    t=tot;
    splay(o,t,0);
    t1[t]=max(t1[t],y);
    t2[t]=max(t2[t],size[t]-1);
}
void del(int x)
{
    int o=pos[x],t=Find(o,x);
    splay(o,t,0);
    if(size[t]==1){root[o]=0;return;}
    int lc=son[t][0],rc=son[t][1];
    if(lc&&!rc){root[o]=lc;fa[lc]=0;return;}
    if(!lc&&rc){root[o]=rc;fa[rc]=0;return;}
    if(!son[t][0])
    {
        root[o]=rc;
        fa[rc]=0;
        return;
    }
    int p=son[t][0];
    while(son[p][1])p=son[p][1];
    splay(o,p,t);
    root[o]=p;fa[p]=0;
    son[p][1]=son[t][1];
    if(son[t][1])fa[son[t][1]]=p;
    up(p);
}
void dfs(int x)
{
    if(!x)return;
    down(x);
    dfs(son[x][0]);
    dfs(son[x][1]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].w=read(),a[i].x=read(),a[i].y=read();
        int t=to(a[i].x,a[i].y);
        Insert(t,i,a[i].w);
        pos[i]=t;
    }
    T=read();
    while(T--)
    {
        int i=read(),x=read(),y=read();
        del(i);
        pos[i]=to(x,y);
        Insert(pos[i],i,a[i].w);
    }
    for(int i=1;i<=cnt;i++)
    if(root[i])dfs(root[i]);
    for(int i=1;i<=n;i++)printf("%lld\n",(LL)(ans1[i])*(LL)(ans2[i]));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值