BZOJ2827 - 千山鸟飞绝

Portal

Description

\(n(n\leq10^5)\)只鸟分布在二维平面的整点上。每只鸟有威武值、士气值和团结值:威武值是固定的;士气值等于与其在同一位置的其他鸟的威武值的最大值;团结值等于与其在同一位置的其他鸟的只数。接下来\(t(t\leq2.5\times10^5)\)秒,第\(i\)秒会有一只鸟\(b_i\)由原位置飞向\((x_i,y_i)\)。求每只鸟在这\(t\)秒中,最大士气值与最大团结值的乘积。

Solution

用平衡树搞。
对于每个整点维护一棵splay,因为最多出现\(n+t\)个不同的坐标所以可以将每个坐标对应成一个数值,map或者离散化均可。splay维护子树大小\(siz\),子树最大武力值\(maxV\),每个点的目前最大士气值\(ans_1\)和最大团结值\(ans_2\)。第\(i\)秒时按以下顺序进行操作:

  • \(b_i\)从原树中删除。\(b_i\)的离开不会使原位置上的鸟的答案变优,所以不用管它们的\(ans\)
  • \((x_i,y_i)\)对应的splay中所有点的\(ans_1\)\(i\)的武力值取max,\(ans_2\)与该树的大小取max。可以打标记。
  • \(b_i\)\(ans_1\)\((x_i,y_i)\)对应的splay的\(maxV\)取max,\(asn_2\)与该树的大小取max。
  • \(b_i\)插入该树中。直接将\(b_i\)设置为该树的根的父亲就好,因为我们的splay不需要按什么关键字来维护。

\(t\)秒后,将所有标记下放,输出\(ans_1[i]\times ans_2[i]\)

时间复杂度\(O(tlogn)\)

Code

//千山鸟飞绝
#include <cstdio>
#include <map>
#include <queue>
using namespace std;
typedef pair<int,int> pairI;
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0,f=1; char ch=gc();
    while(ch<'0'||'9'<ch) f=ch^'-'?f:-1,ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int const N=1e5+10;
int n; pairI pos[N];
int cnt; map<pairI,int> h;
int rt[N<<2],fa[N],ch[N][2],siz[N];
int maxV[N],val[N],ans1[N],ans2[N];
int tag1[N],tag2[N];
int wh(int p) {return p==ch[fa[p]][1];}
void clear(int p) {fa[p]=ch[p][0]=ch[p][1]=0,siz[p]=1; maxV[p]=val[p]; tag1[p]=tag2[p]=0;}
void update(int p)
{
    int ch0=ch[p][0],ch1=ch[p][1];
    siz[p]=siz[ch0]+1+siz[ch1];
    maxV[p]=max(val[p],max(maxV[ch0],maxV[ch1]));
}
void mark(int p,int t1,int t2)
{
    tag1[p]=max(tag1[p],t1),ans1[p]=max(ans1[p],tag1[p]);
    tag2[p]=max(tag2[p],t2),ans2[p]=max(ans2[p],tag2[p]);
}
void pushdw(int p)
{
    int ch0=ch[p][0],ch1=ch[p][1];
    if(tag1[p]) mark(ch0,tag1[p],0),mark(ch1,tag1[p],0),tag1[p]=0;
    if(tag2[p]) mark(ch0,0,tag2[p]),mark(ch1,0,tag2[p]),tag2[p]=0;
}
void rotate(int p)
{
    int q=fa[p],r=fa[q],w=wh(p);
    fa[p]=r; if(r) ch[r][wh(q)]=p;
    fa[ch[q][w]=ch[p][w^1]]=q;
    fa[ch[p][w^1]=q]=p;
    update(q),update(p);
}
void pushdwRt(int p) {if(fa[p]) pushdwRt(fa[p]); pushdw(p);}
void splay(int p)
{
    pushdwRt(p);
    for(int q=fa[p];q;rotate(p),q=fa[p]) if(fa[q]) rotate(wh(p)^wh(q)?p:q);
    rt[h[pos[p]]]=p;
}
void ins(pairI c,int p)
{
    pos[p]=c;
    if(!h[c]) {h[c]=++cnt,rt[h[c]]=p; return;}
    int q=rt[h[c]]; 
    ans1[p]=max(ans1[p],maxV[q]);
    ans2[p]=max(ans2[p],siz[q]);
    mark(q,val[p],siz[q]);
    fa[ch[p][0]=q]=p,update(rt[h[c]]=p);
}
void del(int p)
{
    pairI c=pos[p];
    splay(p);
    if(!ch[p][0]) {rt[h[c]]=ch[p][1],fa[rt[h[c]]]=0; return;}
    int q=ch[p][0]; while(ch[q][1]) q=ch[q][1];
    splay(q); fa[ch[q][1]=ch[p][1]]=q; update(q);
}
void pushdwAll(int p)
{
    if(!p) return;
    pushdw(p); pushdwAll(ch[p][0]),pushdwAll(ch[p][1]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        siz[i]=1; maxV[i]=val[i]=read();
        int x=read(),y=read(); ins(pairI(x,y),i);
    }
    int t=read();
    for(int i=1;i<=t;i++)
    {
        int p=read(),x=read(),y=read();
        del(p); clear(p);
        ins(pairI(x,y),p);
    }
    for(int i=1;i<=cnt;i++) pushdwAll(rt[i]);
    for(int i=1;i<=n;i++) printf("%lld\n",(long long)ans1[i]*ans2[i]);
    return 0;
}

P.S.

原以为码量超大,写完发现还可以嘛!
还有万径人踪灭孤舟蓑笠翁独钓寒江雪等你来写哦~

posted @ 2018-03-22 00:28  VisJiao  阅读(256)  评论(1编辑  收藏  举报