牛客第五场 H Interval —— 主席树

题目链接:点我啊╭(╯^╰)╮

题目大意:

     F ( l , r ) = A l & A l + 1 & . . . & A r F(l, r) = A_l \& A_{l+1} \& ... \& A_{r} F(l,r)=Al&Al+1&...&Ar
     S ( l , r ) = { F ( a , b ) ∣ m i n ( l , r ) ≤ a ≤ m a x ( l , r ) } S(l, r) = \{F(a, b) | min(l, r) ≤ a ≤ max(l, r)\} S(l,r)={F(a,b)min(l,r)amax(l,r)}
     Q Q Q 次查询 l l l r r r,求 S ( l , r ) S(l, r) S(l,r)

解题思路:

    一个数字连续作与操作,不同数字最多出现 l o g log log
    因此对每个 a i a_i ai,记录它往左不停作与操作出现的不同数字
    这里我们要查询 S ( l , r ) S(l, r) S(l,r),也就是以 r r r 为右端点,做与操作的不同数字且产生过程都在 l l l 右端
    联想到主席树求区间不同数字的操作
    这里就可以在记录 a i a_i ai 往左不停作与操作出现的不同数字 的同时
    维护产生这些数字的左端点的最大值
    这个最大值 m a x max max 就是我们查询 S ( l , r ) S(l, r) S(l,r) 时, l l l 必须要 ≤ m a x ≤max max
    因为所有的不同数字最多 n l o g n nlogn nlogn 个,因此直接用 m a p map map 维护最大值即可
    时间复杂度: O ( n l o g 2 n + q l o g n ) O(nlog^2n +qlogn) O(nlog2n+qlogn)

#include
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair  pii;
const int maxn = 1e5 + 5;
int T, n, q, lans, tot, root[maxn];
int t[maxn*300], ls[maxn*300], rs[maxn*300];
map  mp, tmp, las;

void update(int &rt, int pre, int pos, int c, int l, int r) {
	if(l>pos || r> 1;
	update(ls[rt], ls[pre], pos, c, l, mid);
	update(rs[rt], rs[pre], pos, c, mid+1, r);
}

int query(int rt, int L, int R, int l, int r) {
	if(l>R || r=L && r<=R) return t[rt];
	int mid = l + r >> 1, ret = 0;
	ret += query(ls[rt], L, R, l, mid);
	ret += query(rs[rt], L, R, mid+1, r);
	return ret;
}

signed main() {
	scanf("%d", &n);
	for(int i=1, x; i<=n; ++i) {
		scanf("%d", &x);
		root[i] = root[i-1];
		mp[x] = i; tmp.clear();
		for(auto j : mp) {
			int fi = j.first, se = j.second;
			tmp[fi & x] = max(tmp[fi & x], se);
		}
		for(auto j : tmp) {
			int fi = j.first, se = j.second;
			if(las[fi] == se) continue;
			update(root[i], root[i], las[fi], -1, 1, n);
			las[fi] = se;
			update(root[i], root[i], las[fi], 1, 1, n);
		}
		mp.swap(tmp);
	}
	scanf("%d", &q);
	while(q--) {
		int l, r;
		scanf("%d%d", &l, &r);
		l = (l ^ lans) % n + 1;
		r = (r ^ lans) % n + 1;
		if(l > r) swap(l, r);
		printf("%d\n", lans = query(root[r], l, r, 1, n));
	}
}

你可能感兴趣的:(ACM,-,主席树,牛客第五场,H,Interval,主席树,区间与)