zoukankan      html  css  js  c++  java
  • 启智树提高组Day2T2 涛涛的集合

    支持四种操作:集合合并,集合加,(原序列上)区间清零,单点查询。其中单点查询有 (10^7) 次,其余 (50000) 次。(n le 2 imes 10^5)

    显然要用到并查集。但是怎么维护原序列上区间清零呢?这需要用到一个小技巧:维护每个点最后被清零的时间,查询就是当前的值减去最后被清零的值。这个可以用分块来维护。于是,单点查询 ( imes 2),区间清零 (=0)

    然后我们需要用一个能够快速 (O(1)) 查并查集的祖先节点,还要支持打集合加标记的并查集。这个可以启发式合并,集合 -> vector,合并的时候直接把小的那个集合的元素全部拿出来改掉信息,下放标记,扔到大的那个里面。注意为了适应大的集合,那些元素可能还要减去大的集合的加法标记。

    总复杂度:(O(q_0sqrt n + nlogn + q_1))

    inline void Pushdown(int cur) {
    	if (tags[cur]) {
    		for (register int i = st[cur]; i <= ed[cur]; ++i)
    			val[i] = tags[cur];
    		tags[cur] = 0;
    	}
    }
    inline void modify(int l, int r, int v) {
    	if (blong[l] == blong[r]) {
    		Pushdown(blong[l]);
    		for (register int i = l; i <= r; ++i)	val[i] = v;
    		return ;
    	}
    	Pushdown(blong[l]); for (register int i = l; i <= ed[blong[l]]; ++i)	val[i] = v;
    	Pushdown(blong[r]); for (register int i = r; i >= st[blong[r]]; --i)	val[i] = v;
    	for (register int i = blong[l] + 1; i < blong[r]; ++i)
    		tags[i] = v;
    }
    int opt[N], X[N], Y[N];
    vector<pair<PII, int> > vt[N];
    int main() {
    	read(n), read(q);
    	for (register int i = 1; i <= n; ++i)	anc[i] = i, vec[i].push_back(i);
    	init();
    	for (register int i = 1; i <= q; ++i) {
    		read(opt[i]); read(X[i]), read(Y[i]);
    		if (opt[i] == 3) {
    			modify(X[i], Y[i], i);
    		} else if (opt[i] == 4) {
    			for (register int j = X[i]; j <= Y[i]; ++j) {
    				int lst = tags[blong[j]] ? tags[blong[j]] : val[j];
    				vt[i].push_back(MP(MP(i, j), 1));
    				vt[lst].push_back(MP(MP(i, j), -1));
    			}
    		}
    	}
    	memset(val, 0, sizeof(val));
    	for (register int i = 1; i <= q; ++i) {
    		if (opt[i] == 1) {
    			X[i] = anc[X[i]]; Y[i] = anc[Y[i]];
    			if (X[i] != Y[i]) {
    				if (vec[X[i]].size() > vec[Y[i]].size()) swap(X[i], Y[i]);
    				for (register unsigned int j = 0; j < vec[X[i]].size(); ++j) {
    					int cur = vec[X[i]][j];
    					anc[cur] = Y[i];
    					vec[Y[i]].push_back(cur);
    					val[cur] += taga[X[i]] - taga[Y[i]];
    				}
    				vec[X[i]].clear();
    			}
    		} else if (opt[i] == 2) {
    			X[i] = anc[X[i]];
    			taga[X[i]] += Y[i];
    		}
    		for (register unsigned int j = 0; j < vt[i].size(); ++j) {
    			int id = vt[i][j].first.first, type = vt[i][j].second;
    			int cur = vt[i][j].first.second;
    			ans[id] += type * (val[cur] + taga[anc[cur]]);
    		}
    	}
    	for (register int i = 1; i <= q; ++i)
    		if (opt[i] == 4)
    			printf("%lld
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    iSCSI又称为IPSAN
    文档类型定义DTD
    HDU 2971 Tower
    HDU 1588 Gauss Fibonacci
    URAL 1005 Stone Pile
    URAL 1003 Parity
    URAL 1002 Phone Numbers
    URAL 1007 Code Words
    HDU 3306 Another kind of Fibonacci
    FZU 1683 纪念SlingShot
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13569296.html
Copyright © 2011-2022 走看看