问题描述
有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: 输出所有节点中,权值最大的节点的权值
输入格式
输入的第一行是一个整数N,代表节点个数。
接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
输出格式
对于操作F1, F2, F3,输出对应的结果,每个结果占一行。
样例输入
3
0 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
样例输出
-10
10
10
数据范围
对于30%的数据,保证 N<=100,Q<=10000
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000
题解
我们来维护一个斜堆。
合并操作和A3就不说了。
先来搞A2。在堆顶放一个Lzay标记即可。但为了保证下放标记,每次在GetFather时都要将该点到堆顶的所有点下放标记(具体见代码中的gf()函数)。
再搞A1我们先删后加。找到这个点的堆顶(过程中下放标记),在合并它(修改的点)的左右儿子,再把它的左右儿子接它的父亲。再修改该点,将该点与堆顶合并。
F1、F2不说,注意下放标记就行。
F3。。。本蒟蒻不会用set和multset,于是用一种叫“垃圾堆”的神奇方法。将每一次修改前的点投入Trash优先队列中,修改后的点投入Query优先队列中。面对询问,只要两个队列的最大元素相同,就删除它们(因为它已经不存在了)。是不是很玄妙?
综上,这真是棘手的操作。太棘手了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
priority_queue<int> qu,tr;
const int Q=666666;
int ls[Q],rs[Q],v[Q],f[Q],lazy[Q],n;
void pd(int x)
{
if((!lazy[x])||(!x))return;
if(ls[x])v[ls[x]]+=lazy[x],lazy[ls[x]]+=lazy[x];
if(rs[x])v[rs[x]]+=lazy[x],lazy[rs[x]]+=lazy[x];
lazy[x]=0;
}
int merge(int x,int y)
{
if((!x)||(!y))return x|y;
pd(x),pd(y);
if(v[x]<v[y])swap(x,y);
rs[x]=merge(rs[x],y);
f[rs[x]]=x;
swap(ls[x],rs[x]);
return x;
}
stack<int> st;
int gf(int x)
{
int WDWDF=x;
st.push(x);
while(f[x]){
x=f[x];
WDWDF=x;
st.push(x);
}
while(st.size())pd(st.top()),st.pop();
return WDWDF;
}
int del(int x)
{
int lls=ls[x],rrs=rs[x],y,fa=f[x],ha;
ha=gf(x);
y=merge(lls,rrs);
ls[x]=rs[x]=f[x]=0;
if(ls[fa]==x)ls[fa]=y;
else rs[fa]=y;
f[y]=fa;
return gf(y);
}
int main()
{
char o;
int i,x,y,m,fx,fy,all=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&v[i]),f[i]=0,qu.push(v[i]);
for(scanf("%d",&m);m;--m)
while(true)
{
o=getchar();
if(o=='A')
{
scanf("%d",&i);
if(i==3){
scanf("%d",&x);
all+=x;
}else
if(i==1){
scanf("%d%d",&x,&y);
int a=gf(x);
tr.push(v[a]);
v[x]+=y;
qu.push(v[merge(del(x),x)]);
}else
if(i==2){
scanf("%d%d",&x,&y);
x=gf(x);
tr.push(v[x]);
v[x]+=y;
lazy[x]+=y;
qu.push(v[x]);
}
break;
}
if(o=='F')
{
scanf("%d",&i);
if(i==3){
while(qu.size()&&tr.size()&&qu.top()==tr.top())
qu.pop(),tr.pop();
printf("%d\n",qu.top()+all);
}else
if(i==2){
scanf("%d",&x);
printf("%d\n",v[gf(x)]+all);
}else{
scanf("%d",&x);
gf(x);
printf("%d\n",v[x]+all);
}
break;
}
if(o=='U')
{
scanf("%d%d",&x,&y);
x=gf(x),y=gf(y);
if(x!=y){
tr.push(v[x]),tr.push(v[y]);
qu.push(v[merge(x,y)]);
}
break;
}
}
return 0;
}