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; }