[超级码力在线编程大赛初赛(二)] 3.区间异或 RMQ经典问题

题目链接:区间异或

题意

给你一个数组num,现在定义一个区间和:左区间的的最大值+右区间的最小值,现在有多组区间,每组区间包含左区间的L1和R1,以及右区间的L2和R2。问各个区间和的异或值是多少。

题解

经典的RMQ问题,一开始看本题的难度是一星,一直以为有什么巧妙的方法能避免用线段树或者ST表解决,思前想后没搞出来,写了一个权值线段树没有记忆化超时了,脑子一直没转过弯来。最后发现还是得用线段树或者ST表的方法解出。

本题其实用线段树维护一个最大值和最小值即可或者维护一个最大值和一个最小值的ST表也行。
两个都能过。

代码

线段树

class Solution {
    
    
public:
	/**
	 * @param num: array of num
	 * @param ask: Interval pairs
	 * @return: return the sum of xor
	 */
	struct Tree
	{
    
    
		int maxx,minn;
	}tree[200010];
	int numt[50010];
	void build(int p,int l,int r)
	{
    
    
		if(l==r) {
    
     tree[p].maxx=numt[l],tree[p].minn=numt[l]; return ;}
		int mid=(l+r)>>1;
		build(p*2,l,mid);
		build(p*2+1,mid+1,r);
		tree[p].maxx=max(tree[p*2].maxx,tree[p*2+1].maxx);
		tree[p].minn=min(tree[p*2].minn,tree[p*2+1].minn);
	}
	int query_max(int p,int l,int r,int ql,int qr)
	{
    
    
		if(ql<=l && qr>=r) return tree[p].maxx;
		int mid=(l+r)>>1;
		int ans=-1;
		if(ql<=mid) ans=max(ans,query_max(p*2, l, mid, ql, qr));
		if(qr>mid) ans=max(ans,query_max(p*2+1, mid+1, r, ql, qr));
		return ans;
	}
	int query_min(int p,int l,int r,int ql,int qr)
	{
    
    
		if(ql<=l && qr>=r) return tree[p].minn;
		int mid=(l+r)>>1;
		int ans=0x3f3f3f3f;
		if(ql<=mid) ans=min(ans,query_min(p*2, l, mid, ql, qr));
		if(qr>mid) ans=min(ans,query_min(p*2+1, mid+1, r, ql, qr));
		return ans;
	}
	int Intervalxor(vector<int> &num, vector<vector<int> > &ask) {
    
    
		// write your code here
		int ans=0;
		int n=num.size();
		for(int i=0;i<n;i++) numt[i+1]=num[i];
		build(1, 1, n);
		for(int i=0;i<ask.size();++i)
		{
    
    
			int l1=ask[i][0],r1=ask[i][1],l2=ask[i][2],r2=ask[i][3];
			int tmp=query_max(1,1,n,l1, r1)+query_min(1,1,n,l2, r2);
			ans^=tmp;
		}
		return ans;
	}
};

ST表

class Solution {
    
    
public:
	/**
	 * @param num: array of num
	 * @param ask: Interval pairs
	 * @return: return the sum of xor
	 */
	int stmax[50010][20],stmin[50010][20];
	void init(vector<int> &num)
	{
    
    
		int n=num.size();
		for(int i=0;i<n;i++) stmax[i][0]=num[i],stmin[i][0]=num[i];
		for(int j=1;(1<<j) <=n; j++)
			for(int i=0;i+(1<<j)-1<n; i++)
			{
    
    
				stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
				stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
			}
	}
	int RMQ_max(int l,int r)
	{
    
    
		int k=0;
		while (1<<(k+1) <=r-l+1) k++;
		return max(stmax[l][k],stmax[r-(1<<k)+1][k]);
	}
	int RMQ_min(int l,int r)
	{
    
    
		int k=0;
		while (1<<(k+1) <=r-l+1) k++;
		return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
	}
	
	int Intervalxor(vector<int> &num, vector<vector<int> > &ask) {
    
    
		// write your code here
		int ans=0;
		init(num);
		for(int i=0;i<ask.size();++i)
		{
    
    
			int l1=ask[i][0]-1,r1=ask[i][1]-1,l2=ask[i][2]-1,r2=ask[i][3]-1;
			int tmp=RMQ_max(l1, r1)+RMQ_min(l2, r2);
			ans^=tmp;
		}
		return ans;
	}
};

猜你喜欢

转载自blog.csdn.net/weixin_44235989/article/details/108308425