bzoj2333 [SCOI2011]棘手的操作

傳送門

事實證明:同時維護並查集和左偏樹裏的父節點是完全錯誤的……
題目的實質是要求可並堆(我用的左偏樹)支持刪除任意點,然後自己就yy了一種刪除操作,大致就是把要刪除的點先加上所有祖先節點上的標記,然後把它的左右子樹合併加到原來的父節點對應的兒子位置上,同時維護父親。
題目還有一個操作是找所有節點中權值最大的那個,我一開始寫了另一個左偏樹來維護,結果搞了好久都沒調出來,看了黃學長的題解發現STL的妙用於是秒改。。其實這個時候把並查集刪掉就能A了。然而我沒刪,結果每次都RE,GG

總結:
並查集和父節點不要同時維護;(這種暴力查找父節點的複雜度應該和不路徑壓縮和按秩合併的並查集差不多,但是並不會T,我也不知道爲什麼,如果有好心人可以在底下留言告訴我,感激不盡)
STL有時能大大簡化代碼複雜度,一定要靈活使用!

CODE:

#include<set>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=3e5+10;
struct node
{
    int num,plus,dis,id;
    node *ch[2],*fa;
    inline void pushdown();
}pool[N],*t[N],*null;
inline void node::pushdown()
{
    if(plus)
    {
        if(ch[0]!=null) ch[0]->plus+=plus,ch[0]->num+=plus;
        if(ch[1]!=null) ch[1]->plus+=plus,ch[1]->num+=plus;
        plus=0;
    }
}
int n,m,x,y,tot,Plus;
multiset<int> s;
inline void getnew(int value,int id)
{
    node *now=pool+ ++tot;
    now->ch[0]=now->ch[1]=now->fa=null;
    now->num=value,now->id=id;
    now->dis=1;
    t[id]=now;
}
inline int find(int x)
{
    while(t[x]->fa!=null) x=t[x]->fa->id;
    return x;
}
int findtag(node *now)
{
    if(now==null) return 0;
    return findtag(now->fa)+now->plus;
}
node *merge(node *x,node *y)
{
    if(x==null) return y;
    if(y==null) return x;
    if(x->num<y->num) swap(x,y);
    x->pushdown(),y->pushdown();
    x->ch[1]=merge(x->ch[1],y);
    x->ch[1]->fa=x;
    if(x->ch[0]->dis<x->ch[1]->dis) swap(x->ch[0],x->ch[1]);
    x->dis=x->ch[1]->dis+1;
    return x;
}
inline node *del(node *now)
{
    node *fa=now->fa,*child=merge(now->ch[0],now->ch[1]);
    now->ch[0]=now->ch[1]=now->fa=null;
    if(fa->ch[0]==now) fa->ch[0]=child;
    else fa->ch[1]=child;
    child->fa=fa;
    return t[find(child->id)];
}
inline void Merge(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y) return;
    if(merge(t[x],t[y])==t[x]) s.erase(s.find(t[y]->num));
    else s.erase(s.find(t[x]->num));
}
inline void change(int x,int y)
{
    node *now=t[x];s.erase(s.find(t[find(x)]->num));
    now->num+=y+findtag(now->fa);now->pushdown();
    s.insert(merge(del(now),now)->num);
}
inline void add(node *root,int y)
{
    s.erase(s.find(root->num));
    root->plus+=y,root->num+=y;
    s.insert(root->num);
}
int main()
{
    null=pool;
    null->ch[0]=null->ch[1]=null->fa=null;
    null->dis=-1;t[0]=null;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%d",&x),getnew(x,i),s.insert(x);
    scanf("%d",&m);
    while(m--)
    {
        char c=getchar();
        while(c<'A'||c>'Z') c=getchar();
        if(c=='A')
        {
            c=getchar();
            if(c=='1') scanf("%d%d",&x,&y),change(x,y);
            else if(c=='2') scanf("%d%d",&x,&y),add(t[find(x)],y);
            else scanf("%d",&x),Plus+=x;
        }
        else if(c=='F')
        {
            c=getchar();
            if(c=='1') scanf("%d",&x),printf("%d\n",t[x]->num+findtag(t[x]->fa)+Plus);
            else if(c=='2') scanf("%d",&x),printf("%d\n",t[find(x)]->num+Plus);
            else printf("%d\n",*--s.end()+Plus);
        }
        else scanf("%d%d",&x,&y),Merge(x,y);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章