首页 > 其他分享 >Codeforces Round 781 (Div. 2) E. MinimizOR (可持久化字典树)

Codeforces Round 781 (Div. 2) E. MinimizOR (可持久化字典树)

时间:2023-06-23 22:55:23浏览次数:55  
标签:std sz ch MinimizOR idx int Codeforces Div root

传送门

题目大意:

  T组测试数据每组测试数据先输入一个n表示有一个长度为n的一维数组,然后输入n个数字表示这个一维数组。紧接着输入一个k表示有k个询问,对于每个询问会输入一个l和一个r表示询问数组中[l, r]这个区间里面任意两个下标不重复的元素最小的或(|)是多少。

解题思路:

  我们可以贪心的去考虑,如果高位为0一定是最优的。考虑可持久化字典树贪心,从高位往低位尽心贪心,如果[l, r]这个区间里面第x位的代表0这颗子树的大小大于等于2就可以直接往左走最优,若不是的话我们选择直接往右走,此时我们左子树大小最大为1,若为1我们用两个数组rx和ry记录root[l - 1]和root[r]这两个版本此时往左走的编号。因为每走一步最多有一个分支,所以一次查询的时间复杂度最坏为30 * 30。可以通过此题。

#include <bits/stdc++.h>

const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using ll = long long;
typedef std::pair<int, int> PII;
using namespace std;

int n, m;

const int N = 1e5 + 10, M = 3e5 + 10;
struct Persistent_Tire{
	int ch[M * 31][2], ver[M  * 31], root[M * 31], idx, sz[M * 31];
	int sigma;
	int rx[N], ry[N];
	
	inline void Init(){
		ver[0] = -1;//边界
		idx = 0;
		sigma = 30;//位数
		ins(root[0], 0, 0, 0);//边界
	}
	
	//当前版本的root,上个版本的root,值, 当前版本的编号
    inline void ins(int &xx, int o, int v, int pos) {
        sz[xx = ++ idx] = sz[o] + 1;
		ver[idx] = pos;
        for(int d = sigma, c, x = xx; d >= 0; d --){
        	c = (v >> d) & 1;
        	ch[x][c ^ 1] = ch[o][c ^ 1];
        	sz[x = ch[x][c] = ++ idx] = sz[o = ch[o][c]] + 1;
        	ver[idx] = pos;
        }
    }
	
	inline int query(int x, int y, int d) {
		if (d < 0) return 0;
		int lsz = sz[ch[y][0]] - sz[ch[x][0]];
		//std::cout << d << ' ' << lsz << '\n';
		for (int i = 1; i <= m; i ++) 
			lsz += sz[ch[ry[i]][0]] - sz[ch[rx[i]][0]];
		
		if (lsz >= 2) {
			for (int i = 1; i <= m; i ++) {
				ry[i] = ch[ry[i]][0];
				rx[i] = ch[rx[i]][0];
			}
			
			return query(ch[x][0], ch[y][0], d - 1);
		} else {
			for (int i = 1; i <= m; i ++) {
				if (sz[ch[ry[i]][0]] - sz[ch[rx[i]][0]]) {
					ry[i] = ch[ry[i]][0];
					rx[i] = ch[rx[i]][0];
				} else {
					ry[i] = ch[ry[i]][1];
					rx[i] = ch[rx[i]][1];
				}
			}
			
			if (sz[ch[y][0]] - sz[ch[x][0]]) {
				rx[++ m] = ch[x][0];
				ry[m] = ch[y][0];
			}
			
			return (1 << d) + query(ch[x][1], ch[y][1], d - 1);
		}
	}
	
}HT;


inline void solve() {
	HT.Init();
	std::cin >> n;
	
	auto &root = HT.root;
	for (int i = 1, x; i <= n; i ++) {
		std::cin >> x;
		HT.ins(root[i], root[i - 1], x, i);
	}
	
	std::cin >> n;
	
	for (int i = 1; i <= n; i ++) {
		int l, r;
		std::cin >> l >> r;
		m = 0;
		std::cout << HT.query(root[l - 1], root[r], 30) << '\n';
	}
}


int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    
    int _ = 1;
    std::cin >> _;
    while (_ --) solve();
    
    return 0;
}

标签:std,sz,ch,MinimizOR,idx,int,Codeforces,Div,root
From: https://www.cnblogs.com/qdhys/p/17500439.html

相关文章

  • Codeforces Round 881 (Div
    E.TrackingSegments给定初始长度为n,且全为0的序列a,然后给出m个线段,如果一个线段中1的个数严格大于0的个数,那么该线段称为一个漂亮线段,现在给出q次操作,每次操作使得序列a中位置x上的0变为1,请你求出第一次使得所有线段中出现漂亮线段的询问题解:二分答案容易发现答案具有单......
  • Codeforces 1603D. Artistic Partition
    题目链接:D-ArtisticPartition题目大意:要求将\([1,n]\)分成\(k\)段,使得每段对应的\(c(l,r)\)之和最小,其中\(c(l,r)=\sum_{i=l}^r\sum_{j=i}^r[\gcd(i,j)\gel]\)。首先注意到当\(r<2l\)时,\(c(l,r)=r-l+1\)。所以当\(2^k-1\gen\)时答案即为\(n\)。考虑\(\texttt......
  • Codeforces Round 766 (Div. 2) 比赛报告
    0比赛经过比赛还没开始的时候就感觉状态不太好。果然。总归到底都是一个心态问题。A题经过看A题,结果半天看不懂,一开始没有注意到一定要在黑格子上操作。扔到DeepL上翻译了一下,再手玩一下样例就做出来了,速度有点慢。CF怎么这么喜欢出分讨题啊。看题目不能太急,要一个一......
  • Codeforces Round 881 (Div. 3)--F2
    F2.OmskMetro(hardversion)#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;#defineendl"\n"#defineintlonglongconstintN=2e5+5;constintINF=0x3f3f3f3f;//假设一个区间的最大字段和为max最小字段和为min//那么[min,max]区间的......
  • 鼠标悬浮div或者列表li时,展示出button按钮
    <template><divclass="item"><span><inputtype="checkbox":checked="obj.done"@click="handleCheck(obj.id)"></span><span>{{......
  • Codeforces 1835F - Good Graph
    goodproblem,badround。判断YES还是NO很trivial,就直接跑最大匹配看看是不是\(n\)即可。如果是NO,那么考虑Hall定理的证明过程构造即可。具体方法就是找到左部任意一非匹配点,在残量网络上BFS可以到达的点,那所有可以到达的左部点形成的集合就是符合要求的反例。因为你......
  • Codeforces 1835E - Old Mobile
    首先先观察到一个非常浅显的性质:就是一个位置在序列中不是第一次出现,那么到这个位置的时候打出这个字符需要恰好一次按键,这是因为我们肯定在打出第一次出现这个字符的位置的时候已经知道哪个键对应这个字符了,到那个位置的时候直接敲一下就ok了。也就是我们只用关心这个序列中出......
  • Codeforces Round 878 (Div. 3) D. Wooden Toy Festival
    题目翻译:给定一个序列,你可以把序列分为任意的三组不要求顺序,对于每一组序列给出一个数字作为标准,求出序列中和该数字的差绝对值的最大值,现在要求你选顶三个数字使得三个序列的差最大值的最大值最小解题思路:二分,要想方差最小,就让每一组的极差都最小,即最大值减最小值最小#include......
  • 练习记录-cf-Codeforces Round 881 (Div. 3)A-F1
    E是补的太蠢了没想到期末考完的复健A.SashaandArrayColoring题意:可以给不同数字涂上很多颜色,每个颜色的贡献是同一个颜色内的数字最大值和最小值的差思路:排序一遍,取头和尾的差#include<bits/stdc++.h>#defineclosestd::ios::sync_with_stdio(false),cin.tie(0)......
  • CodeForces 合集
    1838E.CountSupersequenceshttps://codeforces.com/contest/1838/problem/E题意给定\(n,m,k\),一个长度为\(n\)的序列\(a=(a_1,a_2,\dots,a_n)\),满足\(1\leqa_i\leqk\),求有多少个序列\(b=(b_1,b_2,\dots,b_m)\),满足\(a\)是\(b\)的一个子序列,并且\(......