事实证明:同时维护并查集和左偏树里的父节点是完全错误的……
题目的实质是要求可并堆(我用的左偏树)支持删除任意点,然后自己就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;
}