【Codeforces 1093E】Intersection of Permutations | 树状数组套权值线段树、动态开点、内存回收

题目大意:

给定整数 n n n和两个 1 , ⋯   , n 1,\cdots ,n 1,,n的排列 a , b a,b a,b

m m m个操作,操作有两种:

  • 1   l a   r a   l b   r b 1\ l_a\ r_a\ l_b \ r_b 1 la ra lb rb,设 a a a [ l a : r a ] [l_a:r_a] [la:ra]区间内元素集合为 S a S_a Sa,设 b b b [ l b : r b ] [l_b:r_b] [lb:rb]区间内元素集合为 S b S_b Sb,求 ∣ S a ∩ S b ∣ |S_a∩S_b| SaSb
  • 2   x   y 2 \ x \ y 2 x y,交换b数组的第 x x x位与第 y y y

1 ≤ n , m ≤ 2 e 5 1 \le n,m \le 2e5 1n,m2e5

题目思路:

写了这场的 F F F G G G,一看 E E E是个数据结构,那也写一下 E E E吧。

其实这题转换一下非常好写的,因为修改操作只对 b b b数组修改,那么就对于 a a a的每一个位置,建立一个在数组 b b b中的权值线段树,映射过去就可以了。

只不过太卡空间了:
【Codeforces 1093E】Intersection of Permutations | 树状数组套权值线段树、动态开点、内存回收_第1张图片

e m m emm emm,然后在坚信自己的思路没问题的情况下,看了下题解,题解的做法挺多的,过几天在补,看了下题解给的主席树写法,增加了空间回收的思路,就去学了一下。

空间回收:树套树写法,复杂度在 l o g 2 n log^2n log2n左右,在每次都修改4次的情况下,基本需要 × 250 \times 250 ×250,但是考虑到一些点权值变为 0 0 0时,这个点就不需要了,所以可以将这个复杂度优化掉。

刚好卡过。

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const int maxn = 2e5+7;
const int mod= 998244353;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
     char c=getchar();T x=0,f=1;while(!isdigit(c)){
     if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
     x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int a[maxn],b[maxn];
int pos[maxn],frc[maxn];
struct node{
     
	int l,r;
	int w;
}t[maxn*220];
vector<int>okNodes;
int cnt = n;
int newNode(){
     
	int u;
	if(okNodes.empty()){
      u=++cnt; return u;}
	u = okNodes.back();
	okNodes.pop_back();
	return u;
}

void insert(int &x,int l,int r,int pos,int w){
     
	if(!x) x = newNode();
	t[x].w += w;
	if(l == r) return;
	int mid = (l+r)/2;
	if(pos<=mid) insert(t[x].l,l,mid,pos,w);
	else insert(t[x].r,mid+1,r,pos,w);
	if(!t[x].w){
     
		okNodes.push_back(x);
		t[x].l = t[x].r = 0;
		x = 0;

	}
}

ll query(int now,int l,int r,int x,int y){
     
	if(!now) return 0;
	if(x<=l && y>=r) return t[now].w;
	ll ans = 0;
	int mid = (l+r)/2;
	if(x<=mid) ans += query(t[now].l,l,mid,x,y);
	if(y>mid) ans += query(t[now].r,mid+1,r,x,y);
	return ans;
}
void update(int pos,int x,int w){
     while(pos<=n) insert(pos,1,n,x,w),pos += pos&-pos;}
ll getsum(int pos,int x,int y){
     
	ll ans = 0;
	while(pos){
     
		ans += query(pos,1,n,x,y);
		pos -= pos&-pos;
	}return ans;
}
int main(){
     
	read(n);read(m);
	cnt = n;
	for(int i=1;i<=n;i++){
     
		read(a[i]);
		frc[a[i]] = i;
	}
	for(int i=1;i<=n;i++){
     
		read(b[i]);
  	pos[b[i]] = i;
  }
  for(int i=1;i<=n;i++) update(i,pos[a[i]],1);
 	for(int i=1;i<=m;i++){
     
 		int op,l1,r1,l2,r2;
 		read(op);read(l1);read(r1);
 		if(op == 1){
     
 			read(l2);read(r2);
 			dl(getsum(r1,l2,r2)-getsum(l1-1,l2,r2));
 		}else{
     
 			int tmpx = frc[b[l1]],tmpy = frc[b[r1]];
 			update(tmpx,l1,-1);
 			update(tmpy,r1,-1);
 			update(tmpx,r1,1);
 			update(tmpy,l1,1);
 			swap(b[l1],b[r1]);
 		}
 	}
  return 0;
}

/**
2 2
-1 -2
4 5
**/

你可能感兴趣的:(可持久化数据结构)