[树状数组][权值线段树] Codeforces 1093E Intersection of Permutations

题目描述

You are given two permutations aa and bb , both consisting of nn elements. Permutation of nn elements is such a integer sequence that each value from 11 to nn appears exactly once in it.

You are asked to perform two types of queries with them:

  • 1~l_a~r_a~l_b~r_b1 la? ra? lb? rb? — calculate the number of values which appear in both segment [l_a; r_a][la?;ra?] of positions in permutation aa and segment [l_b; r_b][lb?;rb?] of positions in permutation bb ;
  • 2~x~y2 x y — swap values on positions xx and yy in permutation bb .

Print the answer for each query of the first type.

It is guaranteed that there will be at least one query of the first type in the input.

输入输出格式

输入格式:

The first line contains two integers nn and mm ( 2 \le n \le 2 \cdot 10^52≤n≤2⋅105 , 1 \le m \le 2 \cdot 10^51≤m≤2⋅105 ) — the number of elements in both permutations and the number of queries.

The second line contains nn integers a_1, a_2, \dots, a_na1?,a2?,…,an? ( 1 \le a_i \le n1≤ai?≤n ) — permutation aa . It is guaranteed that each value from 11 to nn appears in aa exactly once.

The third line contains nn integers b_1, b_2, \dots, b_nb1?,b2?,…,bn? ( 1 \le b_i \le n1≤bi?≤n ) — permutation bb . It is guaranteed that each value from 11 to nn appears in bb exactly once.

Each of the next mm lines contains the description of a certain query. These are either:

  • 1~l_a~r_a~l_b~r_b1 la? ra? lb? rb? ( 1 \le l_a \le r_a \le n1≤la?≤ra?≤n , 1 \le l_b \le r_b \le n1≤lb?≤rb?≤n );
  • 2~x~y2 x y ( 1 \le x, y \le n1≤x,y≤n , x \ne yx≠y ).

输出格式:

Print the answers for the queries of the first type, each answer in the new line — the number of values which appear in both segment [l_a; r_a][la?;ra?] of positions in permutation aa and segment [l_b; r_b][lb?;rb?] of positions in permutation bb .

输入输出样例

输入样例#1:

6 7
5 1 4 2 3 6
2 5 3 1 4 6
1 1 2 4 5
2 2 4
1 1 2 4 5
1 2 3 3 5
1 1 6 1 2
2 4 1
1 4 4 1 3

输出样例#1:

1
1
1
2
0

说明

Consider the first query of the first example. Values on positions [1; 2][1;2] of aa are [5, 1][5,1] and values on positions [4; 5][4;5] of bb are [1, 4][1,4] . Only value 11 appears in both segments.

After the first swap (the second query) permutation bb becomes [2, 1, 3, 5, 4, 6][2,1,3,5,4,6] .

After the second swap (the sixth query) permutation bb becomes [5, 1, 3, 2, 4, 6][5,1,3,2,4,6] .

题解

  • 这就是个二维点数问题,直接上树套树就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 const int N=2e5+10,M=1e6*40;
 6 int n,m,cnt,top,a[N],b[N],d[N],st[N],root[N];
 7 struct node { int num,ch[2]; }e[M];
 8 int lowbit(int x) { return (x)&(-x); }
 9 void add(int &d,int x,int y,int l,int r)
10 {
11     if (!d) d=top?st[top--]:++cnt; e[d].num+=y;
12     if (l==r) return;
13     int mid=l+r>>1;
14     if (x<=mid) add(e[d].ch[0],x,y,l,mid); else add(e[d].ch[1],x,y,mid+1,r);
15     if (!e[d].num) st[++top]=d,d=0;
16 }
17 void add(int x,int y,int v) { for (;x<=n;x+=lowbit(x)) add(root[x],y,v,1,n); }
18 int query(int d,int l,int r,int L,int R)
19 {
20     if (!d) return 0;
21     if (L<=l&&r<=R) return e[d].num;
22     int mid=l+r>>1,tot=0;
23     if (L<=mid) tot+=query(e[d].ch[0],l,mid,L,R);
24     if (R>mid) tot+=query(e[d].ch[1],mid+1,r,L,R);
25     return tot;
26 }
27 int query(int L,int R,int l,int r)
28 {
29     int ans=0;
30     for (int i=L-1;i;i-=lowbit(i)) ans-=query(root[i],1,n,l,r);
31     for (int i=R;i;i-=lowbit(i)) ans+=query(root[i],1,n,l,r);
32     return ans;
33 }
34 int main()
35 {
36     scanf("%d%d",&n,&m);
37     for (int i=1;i<=n;i++) scanf("%d",&a[i]),d[a[i]]=i;
38     for (int i=1,x;i<=n;i++) scanf("%d",&x),b[i]=d[x];
39     for (int i=1;i<=n;i++) add(i,b[i],1);
40     for (int l,r,L,R,op;m;m--)
41     {
42         scanf("%d",&op);
43         if (op==1) scanf("%d%d%d%d",&L,&R,&l,&r),printf("%d\n",query(l,r,L,R));
44         else  scanf("%d%d",&l,&r),add(l,b[l],-1),add(r,b[r],-1),add(l,b[r],1),add(r,b[l],1),swap(b[l],b[r]);
45     }
46 }

原文地址:https://www.cnblogs.com/Comfortable/p/11206582.html

时间: 2024-11-06 03:48:12

[树状数组][权值线段树] Codeforces 1093E Intersection of Permutations的相关文章

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT

[模板]树状数组1/ZKW线段树

https://www.luogu.org/problemnew/show/P3374 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define rson (o<<1|1) 5 #define lson (o<<1) 6 const int N = 530000<<1;//zkw线段树只能查询(0,bit),所以只有bit-2个叶节点,bit-2<n

【刷题】【数据结构】【树状数组】【线段树】

1>数星星 (复制自他人博客) 由于题目中给的数据是按y轴排序,我们只需构建x轴的树状数组,也就是说我们只需统计星星i之前一共有多少个x坐标小于或等于Xi的星星,这个数值也就是星星i的等级 又因为树状数组无法处理下标为0的元素(会死循环),所以要把每个x坐标+1 #include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; int max(int a,int b) { ret

BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

题目大意:有一些位置,这些位置上可以放若干个数字.现在有两种操作. 1.在区间l到r上添加一个数字x 2.求出l到r上的第k大的数字是什么 思路:这种题一看就是树套树,关键是怎么套,怎么写.(话说我也不会来着..)最容易想到的方法就是区间线段树套一个权值线段树,但是区间线段树上的标记就会变得异常复杂.所以我们就反过来套,用权值线段树套区间线段树.这样修改操作在外线段树上就变成了单点修改,外线段树就不用维护标记了.在里面的区间线段树上维护标记就容易多了.具体实现见代码. CODE: #includ

详解权值线段树

详解权值线段树 本篇随笔详细讲解一下算法竞赛中的一种数据结构--权值线段树. 前置知识 在讲解权值线段树之前,我们首先要明确:权值线段树属于一种线段树,它的本质仍然是线段树.所以在学习权值线段树之前,如果还对普通线段树并没有一个深刻的了解的话,请先移步这篇博客来学习简单线段树. 简单线段树知识点详解 以及,权值线段树的本质是线段树维护桶.这个桶到底是什么呢?如果读者对桶的概念和应用比较模糊的话,请移步这篇博客来学习桶的基本概念和应用: 桶的基本概念和应用 权值线段树的概念 那么,在了解了所有的前

树状数组求区间最大值(树状数组)(复习)

如题. 当遇到单点更新时,树状数组往往比线段树更实用. 算法: 设原数序列为a[i],最大值为h[i](树状数组). 1.单点更新: 直接更新a[i],然后再更新h[i].若h[i]的值有可能改变的,则表示区间一定包含i结点.那么就两层lowbit更新所有可能的h. 单点更新时间复杂度O(logn*logn) 1 void update(int x) 2 { 3 while(x<=n) 4 { 5 h[x]=a[x]; 6 for(int i=1;i<lowbit(x);i<<=1

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons