洛谷 P4883 mzf的考验 简易题解【fhq treap】

【题目链接】


         \ \ \ \ \ \ \,       首先我们看他的操作:

  • o p t = = 1 opt==1 opt==1:两个正整数: l l l r r r。请翻转区间 [ l , r ] [l,r] [l,r]
  • o p t = = 2 opt==2 opt==2:三个正整数: l l l r r r d d d。请将区间 [ l , r ] [l,r] [l,r]中的所有卦象都异或卦象 d d d;
  • o p t = = 3 opt==3 opt==3:两个正整数: l l l r r r。请查询区间 [ l , r ] [l,r] [l,r]的卦象权值和。

         \ \ \ \ \ \ \,       显然是一个平衡树可以做的啦,我们试着选择 F h q _ t r e a p Fhq\_treap Fhq_treap 做一下:

         \ \ \ \ \ \ \,       对于操作 1 1 1 3 3 3 操作很简单,我们 p u s h u p pushup pushup 一下子树和, p u s h d o w n pushdown pushdown 一下旋转标记,提出区间 [ l , r ] [l,r] [l,r] 进行对应的操作就可以了。

         \ \ \ \ \ \ \,       那么对应的 2 2 2 操作似乎没有那么简单操作了,我们先看看我们需要修改的 p u s h d o w n pushdown pushdown 操作是什么:

  1. 单点权值 ( v a l ) (val) (val):直接异或上修改的值,在 p u s h d o w n pushdown pushdown操作的时候同理。
  2. 权值懒人标记 ( l a z y _ w ) (lazy\_w) (lazy_w):直接异或上修改的值,在 p u s h d o w n pushdown pushdown操作的时候同理。
  3. 子树和 ( s u m ) (sum) (sum):?

         \ \ \ \ \ \ \,       可以发现子树和的处理特别麻烦,但是对于异或问题,我们通常可以拆位解决,对于每一个节点,我们新开一个数组 n u m [ i ] num[i] num[i] ,表示这个子树内的值,数位 i i i 上面为 1 1 1 的值是多少,这个很显然,我们可以通过 p u s h u p pushup pushup 一并传递上去。

         \ \ \ \ \ \ \,       如何处理子树和呢?因为打了标记的子树都要异或这一个值,所以我们把这个值拆了,如果这一位为 1 1 1 ,那么子树这一位都会 1 1 1 0 0 0 0 0 0 1 1 1,所以说有:

n u m [ i ] = s i z e − n u m [ i ] num[i]=size-num[i] num[i]=sizenum[i]

         \ \ \ \ \ \ \,       其中 s i z e size size为子树大小,修改了 n u m num num数组之后,我们就可以重新计算子树和了:

s u m = ∑ i = 0 l i m i t 2 i × n u m [ i ] sum=\sum_{i=0}^{limit}2^i\times num[i] sum=i=0limit2i×num[i]

         \ \ \ \ \ \ \,       所以 p u s h u p pushup pushup p u s h d o w n pushdown pushdown 差不多应该是这样的:

void Xor(int rt,int x){
	lazy_w[rt]^=x;val[rt]^=x;
    sum[rt]=0;
	for(int i=0;i<=20;++i)tmp[i]=(x>>i)&1;
  	for(int i=0;i<=20;++i){
      	if(tmp[i])num[rt][i]=size[rt]-num[rt][i];
      	sum[rt]+=(1ll<<i)*num[rt][i];
    }
}
void pushup(int rt){
	size[rt]=size[lson]+size[rson]+1;
	sum[rt]=sum[lson]+sum[rson]+1ll*val[rt];
	for(int i=0;i<=20;i++)
	num[rt][i]=num[lson][i]+num[rson][i]+((val[rt]>>i)&1);
}
void pushdown(int rt){
	if(lazy[rt]){
		swap(lson,rson);
		if(lson)lazy[lson]^=1;
		if(rson)lazy[rson]^=1;
		lazy[rt]=0;
	}
	if(lazy_w[rt]){
		int x=lazy_w[rt];lazy_w[rt]=0;
		if(lson){Xor(lson,x);}
		if(rson){Xor(rson,x);}
	}
}

       &ThinSpace; \ \ \ \ \ \ \,       总期望复杂度应该是 O ( n log ⁡ n   l i m i t ) O(n\log n\ limit) O(nlogn limit),其中 l i m i t = log ⁡ v a l limit=\log val limit=logval

       &ThinSpace; \ \ \ \ \ \ \,       懒得卡常了,吸氧过:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<map>
#include<set>
using namespace std;
const int inf=0x7fffffff;
const double eps=1e-10;
const double pi=acos(-1.0);
//char buf[1<<15],*S=buf,*T=buf;
//char getch(){return S==T&&(T=(S=buf)+fread(buf,1,1<<15,stdin),S==T)?0:*S++;}
inline int read(){
	int x=0,f=1;char ch;ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=0;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch&15);ch=getchar();}
	if(f)return x;else return -x;
}
const int N=1e5+10;
struct fhq_treap{
	#define lson ls[rt]
	#define rson rs[rt]
	int ls[N],rs[N];
	bool lazy[N];
	int lazy_w[N],val[N],key[N],size[N];
	long long sum[N];
	int root,cnt;
	int tmp[25],num[N][25];
	void Xor(int rt,int x){
		lazy_w[rt]^=x;val[rt]^=x;
    	sum[rt]=0;
		for(int i=0;i<=20;++i)tmp[i]=(x>>i)&1;
  		for(int i=0;i<=20;++i){
      		if(tmp[i])num[rt][i]=size[rt]-num[rt][i];
      		sum[rt]+=(1ll<<i)*num[rt][i];
    	}
	}
	void pushup(int rt){
		size[rt]=size[lson]+size[rson]+1;
		sum[rt]=sum[lson]+sum[rson]+1ll*val[rt];
		for(int i=0;i<=20;i++)
		num[rt][i]=num[lson][i]+num[rson][i]+((val[rt]>>i)&1);
	}
	void pushdown(int rt){
		if(lazy[rt]){
			swap(lson,rson);
			if(lson)lazy[lson]^=1;
			if(rson)lazy[rson]^=1;
			lazy[rt]=0;
		}
		if(lazy_w[rt]){
			int x=lazy_w[rt];lazy_w[rt]=0;
			if(lson){Xor(lson,x);}
			if(rson){Xor(rson,x);}
		}
	}
	int merge(int a,int b){
		if(!a||!b)return a|b;
		if(key[a]<key[b]){pushdown(a);rs[a]=merge(rs[a],b);pushup(a);return a;}
		else {pushdown(b);ls[b]=merge(a,ls[b]);pushup(b);return b;}
	}
	void split(int rt,int x,int &a,int &b){
		if(!rt){a=b=0;return;}
		pushdown(rt);
		if(x<=size[lson]){b=rt;split(lson,x,a,lson);}
		else {a=rt;split(rson,x-size[lson]-1,rson,b);}
		pushup(rt);
	}
	int newnode(int x){
		int rt=++cnt;
		size[rt]=1;val[rt]=x;key[rt]=rand();
		lazy[rt]=0;lazy_w[rt]=0;
		lson=rson=0;
		return rt;
	}
	int build(int a[],int len){
		stack<int> S;
		int rt,last;
	  	for(int i=1;i<=len;i++){
	    rt=newnode(a[i]);last=0;
	    while(!S.empty()&&key[S.top()]>key[rt])
			pushup(last=S.top()),S.pop();
	    	if(!S.empty())rs[S.top()]=rt;
	    	lson=last;S.push(rt);
	  	}
	  	while(!S.empty())pushup(last=S.top()),S.pop();
	  	return last; 
	}
	void Revers(int l,int r){
		int a,b,c;
		split(root,r,a,c);
		split(a,l-1,a,b);
		lazy[b]^=1;
		root=merge(merge(a,b),c);
	}
	void Update(int l,int r,int d){
		int a,b,c;
		split(root,r,a,c);
		split(a,l-1,a,b);
		Xor(b,d);
		root=merge(merge(a,b),c);
	}
	long long Query(int l,int r){
		int a,b,c;
		split(root,r,a,c);
		split(a,l-1,a,b);
		long long ret=sum[b];
		root=merge(merge(a,b),c);
		return ret;
	}
}Tree;
int n,m;
int a[N],op,l,r,d;
int main()
{
	srand(time(NULL));
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	Tree.root=Tree.build(a,n);
	while(m--){
		op=read();l=read();r=read();
		if(op==1)Tree.Revers(l,r);
		if(op==2)d=read(),Tree.Update(l,r,d);
		if(op==3)cout<<Tree.Query(l,r)<<endl;
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我无法直接解码 Base64 编码的字符串,因为我无法处理二进制数据。然而,如果您使用标准的 C 语言库,您可以使用 `<stdlib.h>` 和 `<stdio.h>` 头文件中的函数来解码 Base64 字符串。 以下是一个简单的示例代码,使用 C 标准库函数来解码 Base64 编码的字符串: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int base64_decode(const char *encoded_data, size_t encoded_length, unsigned char *decoded_data, size_t *decoded_length) { int i, j; unsigned char a, b, c, d; if (encoded_length % 4 != 0) { return -1; // Invalid Base64 string } *decoded_length = (encoded_length / 4) * 3; for (i = 0, j = 0; i < encoded_length; i += 4, j += 3) { a = strchr(base64_chars, encoded_data[i]) - base64_chars; b = strchr(base64_chars, encoded_data[i+1]) - base64_chars; c = strchr(base64_chars, encoded_data[i+2]) - base64_chars; d = strchr(base64_chars, encoded_data[i+3]) - base64_chars; decoded_data[j] = (a << 2) | (b >> 4); decoded_data[j+1] = (b << 4) | (c >> 2); decoded_data[j+2] = (c << 6) | d; } return 0; } int main() { const char *encoded_data = "bXNjaAF4nFVS3U/TUBQ/Xbu2ax08+Cfw3MgSCPGRGPZPLDwU2mDN1s52hfhs/HhBEiMmk4iiA2aMfGTTTWbg3T9Dd9sRTXg3YD3nVti4ye2953c+fuf0/mAcciJIrlmxQS9MssZu/KbF3jVBt+xg0XeqNcdzAUAumwt2OYBs6ezt53kNxhZ8x1qyjUXPtUKnBnolLNcco+rbQQA3q2UzqJmuE1YoYNl+4PmgVb0V2zdcz7IhX3buh45l+F5Ys30YHxZLY8f/+++F7iJvQA3dsmdaGKtXzCAwLN9ZRkOpIJ25ZGODt4CWglukiyiAAJn0LhEKSZKcc1ROUXWIZhDFFBEPSZW4W0ougG4y4hLiKohZrAdKkvz9jXubmyOVZTRVShXTLmhlRAVNIQuQ5Y4MZf/C/R4bkag++eUrv0KJEm+fuFWaIovk/MBQFT8S1Yhxb2HbfFw6BGpPSQliTkCmPGyPmlIuvZvcVIdsAuRSmhzRCKDx2UG/Pop+NYqeMv3kTORIZ8jhTZEE+D4iJG3Qbp5+OIx6W9H608HJRvSyzlZbbG1f6/eesc5O/3h30NmPXxyyepPcB22N9Y4Ge3v9biPunbDuDntyNGjvaoZRmpicnJsu4pqPNtdZoz3Yb7Ptr/3uavSwdfr4uVZauevU7PmF+GOdPWpFrebZt1elieLs7GxxCpPiT4enG81+9ws7WIvq7cvw+LjB1jo89M5cEaMxdGZmunB7eqYwBTSsejnsa/ytN1IR/OAiECBPKiP0msrypDIJUZXeJ5+qK0/qQl1Bcp5cJOcgJn8QlxHnwhnjhckPqSmNPt/YqGD/ATJ9J5E="; size_t encoded_length = strlen(encoded_data); size_t decoded_length = 0; // 计算解码后的数据长度 base64_decode(encoded_data, encoded_length, NULL, &decoded_length); // 分配内存 unsigned char *decoded_data = malloc(decoded_length + 1); if (decoded_data == NULL) { printf("内存分配失败\n"); return 1; } // 进行解码 if (base64_decode(encoded_data, encoded_length, decoded_data, &decoded_length) != 0) { printf("解码失败\n"); free(decoded_data); return 1; } // 打印解码后的数据 printf("解码后的数据: %s\n", decoded_data); // 释放内存 free(decoded_data); return 0; } ``` 请注意,这只是一个简单的示例代码,可能无法处理所有情况。如果您需要更复杂的 Base64 解码功能,建议使用第三方库或更完善的解码实现。希望这可以帮助到您!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值