【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=1; tag=0; mx=w=_w; }
	void up() { if(this==null) return; s=c[0]->s+c[1]->s+1; mx=max(w, max(c[0]->mx, c[1]->mx)); }
	void upd(int add) { if(this==null) return; mx+=add; w+=add; tag+=add; }
	void down() { if(tag) c[0]->upd(tag), c[1]->upd(tag), tag=0; }
	bool d() { return f->c[1]==this; }
	void setc(node *x, int d) { c[d]=x; x->f=this; }
}Po[Lim], *iT=Po, *p[N];
node *newnode(int w=-(~0u>>2)) { iT->init(w); return iT++; }
void rot(node *x) {
	node *f=x->f; f->down(); x->down(); bool d=x->d();
	if(f->f!=null) f->f->setc(x, f->d());
	else x->f=f->f;
	f->setc(x->c[!d], d);
	x->setc(f, !d);
	f->up();
}
void splay(node *x, node *goal) {
	if(x==null) return;
	while(x->f!=goal)
		if(x->f->f==goal) rot(x);
		else x->d()==x->f->d()?(rot(x->f), rot(x)):(rot(x), rot(x));
	x->up();
}
int getrank(node *x) { splay(x, null); return x->c[0]->s; }
node *sel(int k, node *x) {
	int s=x->c[0]->s;
	if(s==k) return x;
	if(s<k) return sel(k-s-1, x->c[1]);
	return sel(k, x->c[0]);
}
node *sel(int k) { splay(&Po[1], null); return sel(k, &Po[1]); }
node *getrange(int l, int r) {
	node *nl=sel(l-1), *nr=sel(r+1);
	splay(nl, null); splay(nr, nl); return nr;
}
node *getblc(node *x, int len) { int rk=getrank(x); return getrange(rk, rk+len-1); }

int pf[N], sz[N], wsum, a[N], n;
int find(int x) { return pf[x]==x?x:pf[x]=find(pf[x]); }
void U(int x, int y) {
	int fx=find(x), fy=find(y);
	if(fx==fy) return;
	if(sz[fx]<sz[fy]) swap(x, y), swap(fx, fy);
	sz[fx]+=sz[fy]; pf[fy]=fx;
	node *yf=getblc(p[fy], sz[fy]), *ny=yf->c[0];
	// printf("%d, %d\n", yf, ny);
	yf->c[0]=null; ny->f=null;
	splay(yf, null);
	splay(p[fx], null);
	splay(sel(p[fx]->c[0]->s+1), p[fx]);
	p[fx]->c[1]->setc(ny, 0);
	splay(ny, null);
}
void A1(int x, int v) { splay(p[x], null); p[x]->w+=v; p[x]->up(); }
void A2(int x, int v) { x=find(x); node *y=getblc(p[x], sz[x]); y->c[0]->upd(v); splay(y->c[0], null); }
void A3(int v) { wsum+=v; }
int F1(int x) { splay(p[x], null); return p[x]->w; }
int F2(int x) { int rt=find(x); node *y=getblc(p[rt], sz[rt]); return y->c[0]->mx; }
int F3() { splay(&Po[1], null); return Po[1].mx; }
node *build(int l, int r) {
	if(l>r) return null;
	int mid=(l+r)>>1;
	node *x=p[mid]=newnode(a[mid]), *nl=build(l, mid-1), *nr=build(mid+1, r);
	if(nl!=null) x->setc(nl, 0);
	if(nr!=null) x->setc(nr, 1);
	x->up();
	return x;
}
void init() {
	null=iT++; null->init(); null->s=0;
	node *l=newnode(), *r=newnode();
	l->setc(r, 1);
	r->setc(build(1, n), 0);
	r->up(); l->up();
	//D(l);
	for(int i=1; i<=n; ++i) pf[i]=i, sz[i]=1;
}
int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; ++i) scanf("%d", &a[i]);
	init();
	int Q; scanf("%d", &Q);
	while(Q--) {
		char cs[5];
		int x, v;
		scanf("%s", cs);
		if(cs[0]==‘A‘) {
			if(cs[1]==‘1‘) scanf("%d%d", &x, &v), A1(x, v);
			else if(cs[1]==‘2‘) scanf("%d%d", &x, &v), A2(x, v);
			else scanf("%d", &v), A3(v);
		}
		else if(cs[0]==‘U‘) scanf("%d%d", &x, &v), U(x, v);
		else {
			int ans;
			if(cs[1]==‘1‘) scanf("%d", &x), ans=F1(x);
			else if(cs[1]==‘2‘) scanf("%d", &x), ans=F2(x);
			else ans=F3();
			printf("%d\n", ans+wsum);
		}
		//puts("");
		//splay(&Po[1], null);
		//D(&Po[1]);
	}
	return 0;
}

  

其实我是直接输入2333来做的233333333

想了一下发现可以用splay来做0.0

大概就是维护一个序列,然后同一连通块在一段连续的区间,然后区间修改就行辣

然后连通块大小用并查集维护一下就行辣

(然后看到题解是一堆可并堆是什么鬼。。。。可并堆是什么.......QAQ

(窝看了一下,妈呀你们这个左偏树查询和深度有关,居然没被卡!!!差评!!然后我的splay是单次查询是$O(logn)$的居然还被卡常熟!!!!!!

时间: 2024-08-28 15:58:24

【BZOJ】2333: [SCOI2011]棘手的操作的相关文章

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的时候要把

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个节点所在的连通块的所有

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

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 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个节点所在的连通块的所有

bzoj2333[SCOI2011]棘手的操作

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

bzoj千题计划217:bzoj2333: [SCOI2011]棘手的操作

http://www.lydsy.com/JudgeOnline/problem.php?id=2333 读入所有数据,先模拟一遍所有的合并操作 我们不关心联通块长什么样,只关心联通块内有谁 所以可以把一个联通块用一个链表存储 合并x和y时,y的链表整体接到x的链表后面 这样就成了线性结构 按照链表顺序重新给序列标号即可用线段树维护 一遍过,^_^ #include<cstdio> #include<iostream> #include<algorithm> using

bzoj千题计划218:bzoj2333: [SCOI2011]棘手的操作

http://www.lydsy.com/JudgeOnline/problem.php?id=2333 上次那个是线段树,再发一个左偏树 维护两种左偏树 第一种是对每个联通块维护一个左偏树 第二种是对所有第一种左偏树的根节点维护一个左偏树 #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 300001 /*void read(int &x

【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: 输