Description
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:
U x y: 加一条边,连接第x个节点和第y个节点
A1 x v: 将第x个节点的权值增加v
A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v
A3 v: 将所有节点的权值都增加v
F1 x: 输出第x个节点当前的权值
F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值
F3: 输出所有节点中,权值最大的节点的权值
Input
输入的第一行是一个整数N,代表节点个数。
接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
Output
对于操作F1, F2, F3,输出对应的结果,每个结果占一行。
Sample Input
0 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
Sample Output
10
10
HINT
对于30%的数据,保证 N<=100,Q<=10000
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000
Solution
第一眼:这不splay启发式合并板子题吗?
然后就开始漫长的写写写调调调
维护多颗splay
U:splay启发式合并,一个个删除小的splay插入到大的splay里面
A1:删除val[x],插入val[x]+v
A2:开个Add数组,维护每颗splay整体加的数
A3:搞个全局变量ALL记一下就好了
F1:直接输出val[x]+Add[x]+ALL
F2:直接输出Max[ID[x]],其中ID是x所属的平衡树编号
F3::这个相当于要维护Max[]的最大值。开个可删堆,每次Max[i]变化的时候就把旧的删掉,新的插入,F3查询的时候直接输出堆顶即可。
emmm话说为什么大部分人都写的堆啊_(Xз」∠)_
Code
#include<iostream>
#include<cstdio>
#include<queue>
#define N (600000+1000)
using namespace std; int Son[N][],Father[N],Size[N];
int ID[N],Add[N],Val[N],Max[N];
int Root[N],n,m,x,y,v,ALL;
char opt[];
priority_queue<int>Heap,Del; int Get(int x){return Son[Father[x]][]==x;}
void Update(int x){Size[x]=Size[Son[x][]]+Size[Son[x][]]+;}
void Clear(int x){Son[x][]=Son[x][]=Father[x]=Size[x]=Val[x]=;} int Pre(int x)
{
x=Son[x][];
while (Son[x][]) x=Son[x][];
return x;
} int Get_Max(int x)
{
while (Son[x][]) x=Son[x][];
return Val[x];
} void Rotate(int x)
{
int wh=Get(x);
int fa=Father[x], fafa=Father[fa];
if (fafa) Son[fafa][Son[fafa][]==fa]=x;
Son[fa][wh]=Son[x][wh^]; Father[fa]=x;
if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
Son[x][wh^]=fa; Father[x]=fafa;
Update(fa); Update(x);
} void Splay(int x)
{
for (int fa; (fa=Father[x]); Rotate(x))
if (Father[fa])
Rotate(Get(fa)==Get(x)?fa:x);
Root[ID[x]]=x;
} void Insert(int x,int y,int v)
{
int now=Root[ID[y]],fa=;
while ()
{
fa=now,now=Son[now][v>Val[now]];
if (now==)
{
Val[x]=v; Size[x]=; Father[x]=fa; ID[x]=ID[y];
Son[fa][v>Val[fa]]=x; Splay(x); return;
}
}
} void Delete(int x)
{
Splay(x);
if (!Son[Root[ID[x]]][] && !Son[Root[ID[x]]][])
{
Clear(Root[ID[x]]);
Root[ID[x]]=;
return;
}
if (!Son[Root[ID[x]]][])
{
Root[ID[x]]=Son[Root[ID[x]]][];
Clear(Father[Root[ID[x]]]);
Father[Root[ID[x]]]=;
return;
}
if (!Son[Root[ID[x]]][])
{
Root[ID[x]]=Son[Root[ID[x]]][];
Clear(Father[Root[ID[x]]]);
Father[Root[ID[x]]]=;
return;
}
int oldroot=Root[ID[x]];
int pre=Pre(Root[ID[x]]);
Splay(pre);
Son[Root[ID[x]]][]=Son[oldroot][];
Father[Son[oldroot][]]=Root[ID[x]];
Clear(oldroot);
Update(Root[ID[x]]);
} void Merge(int x,int y)
{
if (Son[x][]) Merge(Son[x][],y);
if (Son[x][]) Merge(Son[x][],y);
int val=Val[x]+Add[ID[x]]-Add[ID[y]]; Clear(x);
Insert(x,y,val);
} int main()
{
scanf("%d",&n);
for (int i=; i<=n; ++i)
{
scanf("%d",&x);
ID[i]=i; Val[i]=x; Max[i]=x;
Root[i]=i; Size[i]=; Heap.push(x);
}
scanf("%d",&m);
for (int i=; i<=m; ++i)
{
scanf("%s",opt);
if (opt[]=='U')
{
scanf("%d%d",&x,&y);
if (ID[x]!=ID[y])
{
Del.push(min(Max[ID[x]],Max[ID[y]]));
if (Size[Root[ID[x]]]>Size[Root[ID[y]]]) swap(x,y);
Max[ID[y]]=max(Max[ID[y]],Max[ID[x]]);
Merge(Root[ID[x]],Root[ID[y]]);
}
} if (opt[]=='A' && opt[]=='')
{
scanf("%d%d",&x,&v);
int val=Val[x]+v;
if (Size[Root[ID[x]]]==)
{
Val[x]=val;
Del.push(Max[ID[x]]);
Max[ID[x]]=val+Add[ID[x]];
Heap.push(Max[ID[x]]);
continue;
}
Delete(x); Insert(x,Root[ID[x]],val);
Del.push(Max[ID[x]]);
Max[ID[x]]=Get_Max(Root[ID[x]])+Add[ID[x]];
Heap.push(Max[ID[x]]);
} if (opt[]=='A' && opt[]=='')
{
scanf("%d%d",&x,&v), Add[ID[x]]+=v;
Del.push(Max[ID[x]]);
Max[ID[x]]=Get_Max(Root[ID[x]])+Add[ID[x]];
Heap.push(Max[ID[x]]);
} if (opt[]=='A' && opt[]=='')
scanf("%d",&v),ALL+=v; if (opt[]=='F' && opt[]=='')
scanf("%d",&x), printf("%d\n",Val[x]+Add[ID[x]]+ALL); if (opt[]=='F' && opt[]=='')
{
scanf("%d",&x), printf("%d\n",Max[ID[x]]+ALL);
} if (opt[]=='F' && opt[]=='')
{
while ((!Heap.empty()) && (!Del.empty()) && Heap.top()==Del.top())
Heap.pop(), Del.pop();
printf("%d\n",Heap.top()+ALL);
}
}
}