2333: [SCOI2011]棘手的操作[写不出来]

2333: [SCOI2011]棘手的操作

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1979  Solved: 772
[Submit][Status][Discuss]

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

3

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

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

Source

Day2


可恶

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lc t[x].l
#define rc t[x].r
typedef long long ll;
const int N=3e5+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,Q,x,y,v;
char s[20];

int fa[N];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
struct node{
    int l,r,fa,v,d,size;
}t[N];
int add[N];
//inline void update(int x){t[x].size=t[lc].size+t[rc].size+1;}
void Add(int x,int v){
    t[x].v+=v;
    if(lc) Add(lc,v);
    if(rc) Add(rc,v);
}
int Merge(int x,int y){//printf("Merge %d %d\n",x,y);
    if(x==0||y==0) return x+y;
    if(t[x].v<t[y].v) swap(x,y);
    rc=Merge(rc,y);
//  update(x);printf("MS %d %d\n",x,t[x].size);
    t[rc].fa=x;
    if(t[lc].d<t[rc].d) swap(lc,rc);
    t[x].d=t[rc].d+1;
    return x;
}
int Del(int x){
    int f=t[x].fa,y=Merge(lc,rc);
    t[y].fa=f;
    if(f&&t[f].l==x) t[f].l=y;
    if(f&&t[f].r==x) t[f].r=y;
//  update(f);
    int re=f?find(f):y;
    t[x].l=t[x].r=t[x].fa=t[x].d=0;
    x=f;
    while(x){
        if(t[lc].d<t[rc].d) swap(lc,rc);
        if(t[rc].d+1==t[x].d) break;
        t[x].d=t[rc].d+1;
        x=t[x].fa;
    }
    return re;
}

namespace S{

struct node{
    int l,r,fa,v,d;
}t[N];
int root;
int Merge(int x,int y){//printf("Merge %d %d\n",x,y);
    if(x==0||y==0) return x+y;
    if(t[x].v<t[y].v) swap(x,y);
    rc=Merge(rc,y);
    t[rc].fa=x;
    if(t[lc].d<t[rc].d) swap(lc,rc);
    t[x].d=t[rc].d+1;
    return x;
}
int Del(int x){
    int f=t[x].fa,y=Merge(lc,rc);
    t[y].fa=f;
    if(f&&t[f].l==x) t[f].l=y;
    if(f&&t[f].r==x) t[f].r=y;
    int re=f?find(f):y;
    t[x].l=t[x].r=t[x].fa=t[x].d=0;
    x=f;
    while(x){
        if(t[lc].d<t[rc].d) swap(lc,rc);
        if(t[rc].d+1==t[x].d) break;
        t[x].d=t[rc].d+1;
        x=t[x].fa;
    }//printf("DElre %d\n",re);
    return re;
}

int q[N],head,tail;
inline void lop(int &x){if(x==N) x=1;}
void Heapify(){
    head=tail=1;
    for(int i=1;i<=n;i++) q[tail++]=i;
    int x,y,z;
    while(head!=tail){
        x=q[head++];lop(head);
        if(head!=tail) y=q[head++],lop(head);
        else break;
        z=Merge(x,y);
        q[tail++]=z;lop(tail);
    }
    root=x;
}

}

inline void U(int x,int y){
    x=find(x);y=find(y);
    if(x!=y){
        S::Del(x);
        S::Del(y);//printf("IWantToSeeSize %d %d\n",t[x].size,t[y].size);
        if(t[x].size>t[y].size) swap(x,y);
        Add(x,add[x]-add[y]);
        int z=fa[x]=fa[y]=Merge(x,y);//printf("M %d %d %d %d %d %d\n",x,y,z,t[x].v,t[y].v,t[z].v);
        add[z]=add[y];//printf("hiz %d %d %d %d\n",z,S::t[z].v,S::root,S::t[S::root].v);
        t[z].size=t[x].size+t[y].size;
        S::root=S::Merge(S::root,z);//printf("hiroot %d %d\n",S::root,S::t[S::root].v);
    }
}
inline void A1(int x,int v){
    int fx=find(x);
    S::root=S::Del(fx);

    int _add=add[fx],_size=t[fx].size;
    int y=Del(x);
    t[x].v+=v;//printf("what %d %d\n",x,y);
    int z=fa[x]=fa[y]=Merge(x,y);
    //printf("A1 %d %d %d\nAS %d %d %d\n",x,y,z,t[x].size,t[y].size,t[z].size);
    add[z]=_add;t[z].size=_size;

    S::t[z].v=t[z].v+add[z];
    S::root=Merge(S::root,z);
}
inline void A2(int x,int v){
    x=find(x);
    S::root=S::Del(x);
    add[x]+=v;
    S::t[x].v=t[x].v+add[x];
    S::root=Merge(S::root,x);
}
int ADD;
inline void A3(int v){ADD+=v;}
inline void F1(int x){
    int fx=find(x);
    printf("%d\n",t[x].v+add[fx]+ADD);
}
inline void F2(int x){
    int fx=find(x);
    printf("%d\n",t[fx].v+add[fx]+ADD);
}
inline void F3(){printf("%d\n",S::t[S::root].v+ADD);}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();
    for(int i=1;i<=n;i++){
        t[i].v=S::t[i].v=read();
        t[i].size=1; fa[i]=i;
    }
    t[0].d=S::t[0].d=-1;
    S::Heapify();
    Q=read();//printf("BEGIN\n");
    while(Q--){ //printf("QQQQQQQQQ %d\n",Q);
        scanf("%s",s);
        if(s[0]==‘U‘) x=read(),y=read(),U(x,y);
        if(s[0]==‘A‘){
            x=read();
            if(s[1]==‘1‘) v=read(),A1(x,v);
            if(s[1]==‘2‘) v=read(),A2(x,v);
            if(s[1]==‘3‘) A3(x);
        }
        if(s[0]==‘F‘){
            if(s[1]==‘1‘) x=read(),F1(x);
            if(s[1]==‘2‘) x=read(),F2(x);
            if(s[1]==‘3‘) F3();
        }
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
#define lc t[x].l
#define rc t[x].r
typedef long long ll;
const int N=3e5+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,Q,x,y,v;
char s[20];

struct node{
    int l,r,fa,v,d,add;
}t[N];
inline int find(int x){
    while(t[x].fa) x=t[x].fa;
    return x;
}
inline void pushDown(int x){
    if(t[x].add){
        if(lc) t[lc].v+=t[x].add;
        if(rc) t[rc].v+=t[x].add;
        t[x].add=0;
    }
}
int st[N],top;
inline void PD(int x){
    while(x) st[++top]=x,x=t[x].fa;
    while(top) pushDown(st[top--]);
}

int Merge(int x,int y){
    if(x==0||y==0) return x+y;
    if(t[x].v<t[y].v) swap(x,y);
    pushDown(x);
    rc=Merge(rc,y);
    t[rc].fa=x;
    if(t[lc].d<t[rc].d) swap(lc,rc);
    t[x].d=t[rc].d+1;
    return x;
}
int Del(int x){
    pushDown(x);
    int f=t[x].fa,y=Merge(lc,rc);
    t[y].fa=f;
    if(f&&t[f].l==x) t[f].l=y;
    if(f&&t[f].r==x) t[f].r=y;
    t[x].l=t[x].r=t[x].fa=t[x].d=0;
    x=f;
    while(x){
        if(t[lc].d<t[rc].d) swap(lc,rc);
        if(t[rc].d+1==t[x].d) break;
        t[x].d=t[rc].d+1;
        x=t[x].fa;
    }
    return find(y);
}
multiset<int> S;
inline void U(int x,int y){
    x=find(x);y=find(y);
    if(x!=y){
        if(Merge(x,y)==x) S.erase(t[y].v);
        else S.erase(t[x].v);
    }
}
inline void A1(int x,int v){
    PD(x);
    S.erase(t[find(x)].v);
    t[x].v+=v;
    S.insert(t[Merge(Del(x),x)].v);
}
inline void A2(int x,int v){
    int f=find(x);
    S.erase(t[f].v);
    t[f].add+=v;t[f].v+=v;
    S.insert(t[f].v);
}
int ADD;
inline void F1(int x){
    PD(x);
    printf("%d\n",t[x].v+ADD);
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();
    for(int i=1;i<=n;i++){
        t[i].v=read();
        S.insert(t[i].v);
    }
    t[0].d=-1;
    Q=read();
    while(Q--){
        scanf("%s",s);
        if(s[0]==‘U‘) x=read(),y=read(),U(x,y);
        if(s[0]==‘A‘){
            x=read();
            if(s[1]==‘1‘) v=read(),A1(x,v);
            if(s[1]==‘2‘) v=read(),A2(x,v);
            if(s[1]==‘3‘) ADD+=x;
        }
        if(s[0]==‘F‘){
            if(s[1]==‘1‘) x=read(),F1(x);
            if(s[1]==‘2‘) x=read(),printf("%d\n",t[find(x)].v+ADD);
            if(s[1]==‘3‘) printf("%d\n",*--S.end()+ADD);
        }
    }
}
时间: 2024-12-14 09:09:52

2333: [SCOI2011]棘手的操作[写不出来]的相关文章

2333: [SCOI2011]棘手的操作[离线线段树]

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Status][Discuss] Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通块的所有

BZOJ 2333 SCOI2011 棘手的操作 可并堆套可并堆

题目大意:给定n个节点,每个节点有一个初始权值,维护以下操作: 1.合并两个联通块 2.某个点权值+x 3.某个点所在联通块权值+x 4.所有点权值+x 5.询问某个点的权值 6.询问某个点所在联通块的最大权值 7.询问所有点之间的最大权值 2333333333333333333333333333333333333333333333333333333333333 2333333333333333333333333333333333333333333333333333333333333 23333

BZOJ 2333 SCOI2011 棘手的操作 并查集+可并堆

..题意概述就不写了,各位老爷如果是看着玩的可以去搜一下,如果是做题找来的也知道题干的.实际上是题干无法缩减懒得复制ORZ 首先处理一下集合的合并和单点值查询的问题.使用并查集,对于每个点记录标记d表示这个点的实际值比这个点加入并查集的时候的值w大了多少,对于每个点find的时候把这个点到代表元路径上的点的d(不包括代表元)的d加起来更新这个点的d,每一次查询某个点的当前值的时候就先find就可以直接用w+d+代表元的d(特判这个点是不是代表元)回答.特别注意为了保证正确性在merge的时候要把

【BZOJ】2333: [SCOI2011]棘手的操作

http://www.lydsy.com/JudgeOnline/problem.php?id=2333 #include <bits/stdc++.h> using namespace std; const int N=300015, Lim=N; struct node *null; struct node { node *c[2], *f; int s, tag, mx, w; void init(int _w=-(~0u>>2)) { c[0]=c[1]=f=null; s

bzoj2333[SCOI2011]棘手的操作

bzoj2333[SCOI2011]棘手的操作 题意: 有N个节点,M个操作:连接两个节点.单个节点的权值增加v.节点所在的连通块的所有节点的权值增加v.所有节点的权值增加v.询问节点当前的权值.询问节点所在的连通块中权值最大的节点的权值.询问所有节点中权值最大的节点的权值.N,M≤300000 题解: 可并堆,虽然听说配对堆非常快,但教程太少了不会写,所以去学了斜堆,比较好写.斜堆实际上是一棵二叉树,核心是合并操作,这是一个递归过程,有点像treap的删除操作.斜堆保证复杂度的方法是每次递归合

【bzoj2333】[SCOI2011]棘手的操作 可并堆+STL-set

题目描述 有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,代

【bzoj2333】 SCOI2011—棘手的操作

http://www.lydsy.com/JudgeOnline/problem.php?id=2333 (题目链接) 题意 N个节点维护一些操作.. Solution 我们用可并大根堆进行维护. 对于每个连通块建一个局部可并堆,因为要询问全局最大值,所以还要对全局建一个全局可并堆记录之前局部可并堆堆顶元素. U:合并x所在的堆以及y所在的堆,并在全局堆中删除合并前的局部堆堆顶元素,因为它合并以后已经不是其连通块的堆顶了. A1:在堆中删除,更新后再加入堆 A2:找到其堆顶,对堆顶进行修改并打上

【bzoj2333】 [SCOI2011]棘手的操作 可并堆+lazy标记

2016-05-31  21:45:41 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 (学习了黄学长的代码 有如下操作: 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: 输

bzoj2333 [SCOI2011]棘手的操作(洛谷3273)

题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权值增加vA2 x v: 将第x个节点所在的连通块的所有节点的权值都增加vA3 v: 将所有节点的权值都增加vF1 x: 输出第x个节点当前的权值F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值F3: 输出所有节点中,权值最大的节点的权值 输入输出格式 输入格式: 输入的第一行是一个整数