dls的数据结构-笛卡尔树,st表,带权并查集

笛卡尔树

每次将序列中最小的数当成根,递归左右,对跟左边和右边递归地建树
最大的也是类似的
性质: 
区间最小值:两个端点的lca的值
笛卡尔树的中序遍历是原数组(对一般的二叉搜索树都是成立的)
一个点,一路向上都是父亲的左儿子,然后再是一个的父亲的右儿子,
第一个左儿子是右边第一个大于等于他的,第一个左拐的左边第一个小于等于他的
或者可以想想成,一个点的祖先都比他的子孙要小,左右儿子关系,实际是数组中的相对位置关系
建树:最左边的链维护一个单调栈


#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1e6+10;

int ans[N], tot;



// a存放原序列,top从0开始,右边闭区间
// 建立区间最小值笛卡尔树
// 根节点是stk[1]
int stk[N], top, a[N], l[N], r[N];
int n;

void dfs(int u){
	ans[u] = ++tot;
	if(l[u]) dfs(l[u]);
	if(r[u]) dfs(r[u]);
}
void build(){
	int top = 0;
	for(int i = 1; i <= n; i ++) l[i] = r[i] = 0;
	for(int i = 1; i <= n; i ++){
		int k = top;
		while(k > 0 && a[stk[k]] > a[i] ) k--;
		if(k) r[stk[k]] = i;
		if(k < top) l[i] = stk[k + 1];
		stk[++k] = i;
		top = k; 
	}
	// 把树建出来
	// for(int i = 1; i <= n; i ++){
	// 	if(l[i]) add(i, l[i]);
	// 	if(r[i]) add(i, r[i]);
	// }
	dfs(stk[1]);
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	build();
	for(int  i = 1; i <= n; i ++) printf("%d ", ans[i]);
	puts("");
 	return 0;
}

#include<bits/stdc++.h>

using namespace std;
const int N = 1e6+10;
const int LOGN = 21;


int n, q;
long long val[N], f[22][N];
void init(){
    // 这里注意val可能存在的边界问题
    for(int i = 1; i <= n; i ++) f[0][i] = val[i];
    for(int i = 1; i < LOGN; i ++){
        for(int j = 1; j + (1 << (i - 1)) <= n; j ++){
            f[i][j] = max(f[i - 1][j + (1 << (i - 1))], f[i - 1][j]);
        }
    }
}

unsigned int A, B, C;
inline unsigned int rng61() {
    A ^= A << 16;
    A ^= A >> 5;
    A ^= A << 1;
    unsigned int t = A;
    A = B;
    B = C;
    C ^= t ^ A;
    return C;
}

int main(){
	scanf("%d%d%u%u%u", &n, &q, &A, &B, &C);
	for(int i = 1; i <= n; i ++) val[i] = rng61();
	init();
	long long res = 0;
	while(q --){
		int l =  rng61() % n + 1, r = rng61() % n + 1;
		if(l > r) swap(l, r);
		int len = __lg(r - l + 1);
		res ^= max(f[len][l], f[len][r - (1 << len) + 1]);
	}
	cout << res << endl;
}

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 2e5+10;
int p[N];
LL d[N];

int find(int x){
	if(x != p[x]){
		int t = find(p[x]);
		d[x] += d[p[x]];
		p[x] = t;
	}
	return p[x];
}

int main(){
	int n, q; scanf("%d %d", &n, &q);
	for(int i = 1; i <= n; i ++) p[i] = i;
	LL t = 0;
	while(q --){
		int op; scanf("%d", &op);
		if(op == 1){
			int l, r, x; scanf("%d %d %d", &l, &r, &x);
			l = (l + t) % n + 1;
			r = (r + t) % n + 1;
			int pl = find(l), pr = find(r);
			if(pl != pr){
				p[pl] = pr;
				d[pl] = x + d[r] - d[l];
			}
		}
		else if(op == 2){
			int l, r; scanf("%d %d", &l, &r);
			l = (l + t) % n + 1;
			r = (r + t) % n + 1;
			int pl = find(l), pr = find(r);
			if(pl == pr){
				printf("%lld\n", d[l] - d[r]);
				t = abs(d[l] - d[r]);
			}
		}
	}
	return 0;
}
posted @ 2022-04-14 12:55  牛佳文  阅读(168)  评论(0编辑  收藏  举报