bzoj2333 离线 + 线段树

https://www.lydsy.com/JudgeOnline/problem.php?id=2333

有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: 输出所有节点中,权值最大的节点的权值
题意

 

看起来像一道可并堆的硬核数据结构题。

实际上确实是一道可并堆的数据结构题。

但我不会

 

那我有什么办法,只能用离线 + 线段树做了。

 

离线处理交换位置,保证所有连边的点都相邻,然后直接上区间修改+区间查询。

思路不难,就是写起来有点烦

 
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 3e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
template <class T>
inline bool scan_d(T &ret){
    char c; int sgn;
    if(c = getchar(),c == EOF) return 0;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-')?-1:1;
    ret = (c == '-')?0:(c - '0');
    while(c = getchar(),c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
int N,M,K;
int a[maxn];
struct Node{
    char op[3];
    int x,y;
}node[maxn];
int nxt[maxn],ed[maxn];
int fa[maxn];
int find(int p){
    if(p == fa[p]) return p;
    return fa[p] = find(fa[p]);
}
void Union(int a,int b){
    a = find(a); b = find(b);
    if(a == b) return;
    nxt[ed[a]] = b;
    ed[a] = ed[b];
    fa[b] = a;
}
void init(){
    For(i,1,N) ed[i] = fa[i] = i;
}
int pos[maxn],id[maxn];
struct Tree{
    int l,r;
    int lazy,Max;
}tree[maxn << 2];
void Pushup(int t){
    tree[t].Max = max(tree[t << 1].Max,tree[t << 1 | 1].Max);
}
void Pushdown(int t){
    if(tree[t].lazy){
        tree[t << 1].lazy += tree[t].lazy; tree[t << 1 | 1].lazy += tree[t].lazy;
        tree[t << 1].Max += tree[t].lazy; tree[t << 1 | 1].Max += tree[t].lazy;
        tree[t].lazy = 0;
    }
}
void build(int t,int l,int r){
    tree[t].l = l; tree[t].r = r;
    tree[t].lazy = 0;
    if(l == r){
        tree[t].Max = a[id[l]];
        return ;
    }
    int m = (l + r) >> 1;
    build(t << 1,l,m); build(t << 1 | 1,m + 1,r);
    Pushup(t);
}
void update(int t,int l,int r,int v){
    if(l <= tree[t].l && tree[t].r <= r){
        tree[t].Max += v;
        tree[t].lazy += v;
        return ;
    }
    Pushdown(t);
    int m = (tree[t].l + tree[t].r) >> 1;
    if(r <= m) update(t << 1,l,r,v);
    else if(l > m) update(t << 1 | 1,l,r,v);
    else{
        update(t << 1,l,m,v); update(t << 1 | 1,m + 1,r,v);
    }
    Pushup(t);
}
int query(int t,int l,int r){
    if(l <= tree[t].l && tree[t].r <= r){
        return tree[t].Max;
    }
    Pushdown(t);
    int m = (tree[t].l + tree[t].r) >> 1;
    if(r <= m) return query(t << 1,l,r);
    else if(l > m) return query(t << 1 | 1,l,r);
    return max(query(t << 1,l,m),query(t << 1 | 1,m + 1,r));
}
int main()
{
    Sca(N);
    For(i,1,N) scan_d(a[i]);
    scan_d(M); init();
    for(int i = 0 ; i < M ; i ++ ){
        scanf("%s",node[i].op);
        if(node[i].op[0] == 'F'){
            if(node[i].op[1] == '3') continue;
            scan_d(node[i].x);
        }else if(node[i].op[0] == 'A' && node[i].op[1] == '3'){
            scan_d(node[i].x);
        }else{
            scan_d(node[i].x); scan_d(node[i].y);
        }
        if(node[i].op[0] == 'U') Union(node[i].x,node[i].y);
    }
    int cnt = 0;
    for(int i = 1; i <= N ; i ++){
        if(fa[i] != i) continue;
        for(int j = i; j;j = nxt[j]){
            pos[j] = ++cnt;
            id[cnt] = j;
        }
    }
    build(1,1,N); init();
    int sum = 0;
    for(int i = 0 ; i < M ; i ++){
        if(node[i].op[0] == 'U'){
            Union(node[i].x,node[i].y);
        }
        if(node[i].op[0] == 'A'){
            if(node[i].op[1] == '1'){
                node[i].x = pos[node[i].x];
                update(1,node[i].x,node[i].x,node[i].y);
               // cout << "update" << node[i].x << "  " << node[i].x << "  " << node[i].y << endl;
            }else if(node[i].op[1] == '2'){
                int t = find(node[i].x);
                update(1,pos[t],pos[ed[t]],node[i].y);
              //  cout << "update" << pos[t] << "  " << pos[ed[t]] << "  " << node[i].y << endl;
            }else{
                sum += node[i].x;
            }
        }else if(node[i].op[0] == 'F'){
            if(node[i].op[1] == '1'){
                Pri(query(1,pos[node[i].x],pos[node[i].x]) + sum);
               // cout << "query" << pos[node[i].x] << "  " << pos[node[i].x]  << endl;
            }else if(node[i].op[1] == '2'){
                int t = find(node[i].x);
               // cout << "query" << pos[t] << "  " << pos[ed[t]] << endl;
                Pri(query(1,pos[t],pos[ed[t]]) + sum);
            }else{
                Pri(tree[1].Max + sum);
            }
        }
    }
    #ifdef VSCode
    system("pause");
    #endif
    return 0;
}

 

 

 

posted @ 2018-10-22 15:44  Hugh_Locke  阅读(204)  评论(0编辑  收藏  举报