HDU-6356(线段树)

HDU - 6356 2018 Multi-University Training Contest 5

题目链接:hdu-6356.

题目描述

一个长度为 n n n 的整数序列 a 1 , a 2 , . . . a n a_{1},a_{2},...a_{n} a1,a2,...an,初始值均为0.
先给出 m m m个操作,每个操作为 l i , r i , v i l_{i}, r_{i},v_{i} li,ri,vi,将序列 a a a中区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]中小于 v i v_{i} vi的所有元素更新为 v i v_{i} vi.
求: m m m个操作之后, ⊕ i = 1 n ( i ⋅ a i ) \oplus_{i=1}^{n} (i \cdot a_{i}) i=1n(iai)
这个公式的意思是:所有 ( i ⋅ a i ) (i \cdot a_{i}) (iai)的异或和(为什么还需要特别解释一下呢,因为我开始并没有注意)。

思路

正确思路

因为是比较大小,小的更新,所以记录区间最值与更新值作比较。

具体实现:线段树维护区间的最小值 M i n Min Min和最大值 M a x Max Max. 对于每次更新,如果 v i ≤ v_{i}\leq vi M i n Min Min ,即区间最小值都大于 v i v_{i} vi,说明这个区间不需要更新;如果 v i ≥ v_{i}\geq vi M a x Max Max ,即区间最大值都小于 v i v_{i} vi,说明这个区间需要全部更新。介于二者之间就继续递归。用 l a z y lazy lazy记录待更新值。如果遍历到叶子结点就更新其最大最小值: M i n = m a x ( M i n , v i ) , M a x = m a x ( M a x , v i ) . Min=max(Min, v_{i}),Max =max(Max,v_{i}). Min=max(Min,vi),Max=max(Max,vi). 这里都是取最大。

注意点:由父节点的 l a z y lazy lazy值传给子节点时,子节点要取最大,而不是直接赋值。
对于随机数产生函数,函数里面是 u n s i g n e d   i n t unsigned\,int unsignedint,传到函数里面时就是 i n t int int了,使用前都有取模。
求最终答案时,用区间和即可,开始我直接遍历的树,发现不得行,有些地方可能 l a z y lazy lazy还没有下放,值是不对的。结果应该用 l o n g   l o n g long\,long longlong保存。

代码



#include <bits/stdc++.h>

using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define LL long long
unsigned int X, Y, Z;
const int Mod = (1 << 30);
const int MAXN = 100005;  
struct node {
	int l, r;
	int Min,Max;
}t[MAXN * 4];
int a[MAXN];
int lazy[MAXN * 4];
unsigned int func() { // 随机数产生器 
	X = X ^ (X << 11);
	X = X ^ (X >> 4);
	X = X ^ (X << 5);
	X = X ^ (X >> 14);
	unsigned int W = X ^ (Y ^ Z);
	X = Y;
	Y = Z;
	Z = W;
	return Z;
} 
void push_up(int u) { // 复制时出错 
	t[u].Min = min(t[lson(u)].Min, t[rson(u)].Min);
	t[u].Max = max(t[lson(u)].Max, t[rson(u)].Max);
	return;
}
void build(int l, int r, int u) {
	t[u].l = l;
	t[u].r = r;
	lazy[u] = -1; // 初始化 
	if(l == r) {
		t[u].Min = t[u].Max = 0;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, lson(u));
	build(mid+1, r, rson(u));
	push_up(u);
	return;
}
void push_down(int u) {
	if(lazy[u] != -1) {
		t[lson(u)].Min = max(lazy[u], t[lson(u)].Min);
		t[rson(u)].Min = max(lazy[u], t[rson(u)].Min);
		t[lson(u)].Max = max(lazy[u], t[lson(u)].Max);
		t[rson(u)].Max = max(lazy[u], t[rson(u)].Max);
		lazy[lson(u)] = max(lazy[u], lazy[lson(u)]); // 要和之前的lazy比较 
		lazy[rson(u)] = max(lazy[u], lazy[lson(u)]);
		lazy[u] = -1; 
	}
}
void update(int L, int R, int v, int u) {
	if(t[u].l == t[u].r) {
		t[u].Min = max(t[u].Min, v);
		t[u].Max = max(t[u].Max, v);
		return;
	}
	if(t[u].l >= L && t[u].r <= R) { // 在中间则继续向下寻找更新 
		if(t[u].Min >= v) return;
		if(t[u].Max <= v) {
			t[u].Min = t[u].Max = v;
			lazy[u] = v; 
			return;
		}
	}
	if(t[u].Min >= v) return; //   *QQ* 
	push_down(u);
	int mid = (t[u].l + t[u].r) >> 1;
	if(mid >= L) update(L, R, v, lson(u));
	if(mid < R) update(L, R, v, rson(u));
	push_up(u);
	return;
}
int sum(int u, int pos) { 	// 必须通过函数求值, 
    if (t[u].l == t[u].r){
         return t[u].Min;
    }
    int mid=(t[u].l + t[u].r) >> 1;
    push_down(u); 			// 否则可能未被更新 
    if(pos <= mid) return sum(lson(u), pos);
    else return sum(rson(u), pos);
}
int main() {
	int T, n, m;
	scanf("%d", &T);
	while(T--) {
		int ans = 0;
		scanf("%d%d%u%u%u", &n, &m, &X, &Y, &Z);
		build(1, n, 1);
		for(int i = 1; i <= m; i++) {
			unsigned int f1 = func() % n + 1, f2 = func() % n + 1, V = func() % Mod;
			int L, R;
			L = min(f1, f2); R = max(f1, f2);
			update(L, R, V, 1);	
		}
		for(int i = 1; i <= n; i++) {
			ans ^= 1ll * i * sum(1,i);			
		}
		printf("%lld\n",ans);
	}
	
	return 0;
}

错误点

基本注释的地方都曾经错过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值