有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个节点,标号从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,输出对应的结果,每个结果占一行。
对于30%的数据,保证 N<=100,Q<=10000
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000
Day2
题解:线段树+离线操作。
这道题貌似是可以用可并堆或者堆套堆的,但是我太水了,并不会,只好用线段树来搞一搞啦。
先离线所有询问,对于所有的U操作先进性预处理,按照读入的顺序用并查集把一个连通块内的点并到一起,并不断的更新每个连通块的最后一个节点。然后按照每个连通块的顺序,把同一个连通块中的节点放到一起,然后用线段树维护。
#include
#include
#include
#include
#include
#define N 300003
#define inf 1000000000
using namespace std;
int n,m;
int tr[N*4],delta[N*4],maxn[N*4],a[N];
int op[N],x[N],v[N],sz,pos[N],val[N];
int fa[N],end[N],next[N];
void init()
{
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
char s[10]; scanf("%s",s);
if (s[0]=='A')
{
if (s[1]=='1')
op[i]=2,scanf("%d%d",&x[i],&v[i]);// 将第x个节点的权值增加v
if (s[1]=='2')
op[i]=3,scanf("%d%d",&x[i],&v[i]);//将第x个节点所在的连通块的所有节点的权值都增加v
if (s[1]=='3')
op[i]=4,scanf("%d%d",&v[i]);//将所有节点的权值都增加v
}
if (s[0]=='U')
op[i]=1,scanf("%d%d",&x[i],&v[i]);//加一条边,连接第x个节点和第y个节点
if (s[0]=='F')
{
if (s[1]=='1')
op[i]=5,scanf("%d",&x[i]);//输出第x个节点当前的权值
if (s[1]=='2')
op[i]=6,scanf("%d",&x[i]);//输出第x个节点所在的连通块中,权值最大的节点的权值
if (s[1]=='3')
op[i]=7;// 输出所有节点中,权值最大的节点的权值
}
}
}
int find(int x)
{
if (fa[x]==x)
return x;
fa[x]=find(fa[x]);
return fa[x];
}
void update(int x)
{
tr[x]=max(tr[x<<1],tr[x<<1|1]);
}
void pushdown(int x)
{
if (!delta[x]) return;
delta[x<<1]+=delta[x];
delta[x<<1|1]+=delta[x];
tr[x<<1]+=delta[x];
tr[x<<1|1]+=delta[x];
delta[x]=0;
}
void build(int now,int l,int r)
{
if (l==r)
{
tr[now]=val[l];
return;
}
int mid=(l+r)/2;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void pointchange(int now,int l,int r,int x,int v)
{
if (l==r)
{
tr[now]+=v;
return;
}
pushdown(now);
int mid=(l+r)/2;
if (x<=mid)
pointchange(now<<1,l,mid,x,v);
else
pointchange(now<<1|1,mid+1,r,x,v);
update(now);
}
int findpoint(int now,int l,int r,int x)
{
if (l==r) return tr[now];
pushdown(now);
int mid=(l+r)/2;
if (x<=mid)
findpoint(now<<1,l,mid,x);
else
findpoint(now<<1|1,mid+1,r,x);
}
void query(int now,int l,int r,int ll,int rr,int x)
{
if (l>=ll&&r<=rr)
{
tr[now]+=x;
delta[now]+=x;
return;
}
pushdown(now);
int mid=(l+r)/2;
if (ll<=mid)
query(now<<1,l,mid,ll,rr,x);
if (rr>mid)
query(now<<1|1,mid+1,r,ll,rr,x);
update(now);
}
int qjmax(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&r<=rr)
return tr[now];
pushdown(now);
int mid=(l+r)/2;
int ans=-inf;
if (ll<=mid)
ans=max(ans,qjmax(now<<1,l,mid,ll,rr));
if (rr>mid)
ans=max(ans,qjmax(now<<1|1,mid+1,r,ll,rr));
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
init();
for (int i=1;i<=n;i++)
fa[i]=i,end[i]=i;
for (int i=1;i<=m;i++)
if (op[i]==1)
{
int r1=find(x[i]),r2=find(v[i]);
if (r1==r2) continue;
fa[r2]=r1;//并查集的代表节点
next[end[r1]]=r2;//用next数组连通块中的点连接
end[r1]=end[r2];//记录连通块的结束节点
}
for (int i=1;i<=n;i++)
if (find(i)==i)
{
for (int j=i;j;j=next[j])
sz++,pos[j]=sz,val[sz]=a[j];
}
build(1,1,n);
for (int i=1;i<=n;i++)
fa[i]=i,end[i]=i;
for (int i=1;i<=m;i++)
{
if (op[i]==1)
{
int r1=find(x[i]),r2=find(v[i]);
if (r1==r2) continue;
fa[r2]=r1;
end[r1]=end[r2];
}
if (op[i]==2)
pointchange(1,1,n,pos[x[i]],v[i]);
if (op[i]==3)
query(1,1,n,pos[find(x[i])],pos[end[find(x[i])]],v[i]);
if (op[i]==4)
query(1,1,n,1,n,v[i]);
if (op[i]==5)
printf("%d\n",findpoint(1,1,n,pos[x[i]]));
if (op[i]==6)
printf("%d\n",qjmax(1,1,n,pos[find(x[i])],pos[end[find(x[i])]]));
if (op[i]==7)
printf("%d\n",qjmax(1,1,n,1,n));
}
}
题解:可并堆+set
#include
#include
#include
#include
#include
#include
#define N 300003
#define inf 1000000000
using namespace std;
int fa[N],lch[N],rch[N],size[N],val[N],delta[N],d[N];
int f[N];
int n,m,mx,sum;
multiset p;
int find(int x)
{
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
void pushdown(int now)
{
int l=lch[now]; int r=rch[now];
if (delta[now]) {
if(l) val[l]+=delta[now],delta[l]+=delta[now];
if(r) val[r]+=delta[now],delta[r]+=delta[now];
delta[now]=0;
}
}
int merge(int x,int y)
{
if (!x) return y;
if (!y) return x;
if (val[x]