CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树

求两个数列的子列的交集

Time Limit: 1 Sec

Memory Limit: 256 MB

题目连接

http://acm.uestc.edu.cn/#/problem/show/1104

Description

给两个数列A, B,长度分别为n1, n2,保证A中每个元素互不相同,保证B中每个元素互不相同。。进行Q次询问,每次查找A[l1...r1]和B[l2..r2]的交集 集合 大小是多少。。

比如 A = {1,2,3,4,5,6,7},B = {7,6,5,4,3,2,1}

查询A[2..4]和B[3..5]。。A[2..4] = {2,3,4};B[3..5] = {5,4,3},交集为{3,4},大小为2。。

Input

第一行输入n1,第二行输入n1个数;同样,第三行输入n2,第四行输入n2个数。

第五行输入Q。。接下来Q行输入l1, r1, l2, r2。。

保证 n1, n2, Q在[1, 2×105]范围内,1≤l1≤r1≤n1,1≤l2≤r2≤n2,然后数在[−109,109]范围内。。

Output

输出Q行,表示答案。。

Sample Input

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

Sample Output

2

HINT

题意

题解:

主席树裸题,查询区间小于a的数有多少个就好了

代码:

//qscqesze
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <bitset>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define maxn 200500
#define mod 1001
#define eps 1e-9
#define pi 3.1415926
int Num;
//const int inf=0x7fffffff;
const ll inf=999999999;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//*************************************************************************************
int a[maxn],b[maxn],lb,n,m;
struct segmenttree
{
    int l,r,s;
}tree[maxn*25];
int node;
int root[maxn];
int search(int x)
{
    int l=0,r=lb,mid;
    while (l<r)
    {
        mid=l+r+1>>1;
        if(b[mid]<=x) l=mid;
        else r=mid-1;
    }
    return l;
}
int build(int l,int r)
{
    int k=++node;
    tree[k].s=0;
    if(l==r) return k;
    int m=l+r>>1;
    if(l<=m) tree[k].l=build(l,m);
    if(r>m) tree[k].r=build(m+1,r);
    return k;
}
int change(int rt,int l,int r,int x)
{
    int k=++node,root=k,mid;
    tree[k]=tree[rt];
    tree[k].s++;
    while (l<r)
    {
        mid=l+r>>1;
        if(x<=mid)
        {
            rt=tree[rt].l;
            tree[k].l=++node;
            k=node;
            tree[k]=tree[rt];
            tree[k].s++;
            r=mid;
        }
        else
        {
            rt=tree[rt].r;
            tree[k].r=++node;
            k=node;
            tree[k]=tree[rt];
            tree[k].s++;
            l=mid+1;
        }
    }
    return root;
}
int query(int L,int R,int l,int r,int x)
{
    int mid,ans=0;
    while (l<r)
    {
        mid=l+r>>1;
        if(mid>=x)
        {
            r=mid;
            L=tree[L].l;
            R=tree[R].l;
        }
        else
        {
            l=mid+1;
            ans+=tree[tree[R].l].s-tree[tree[L].l].s;
            L=tree[L].r;
            R=tree[R].r;
        }
    }
    if(l==r)
    {
        if(x<l) return 0;
        else return ans+tree[R].s-tree[L].s;
    }
}
int get(int l,int r,int val)
{
    val = search(val);
    if(val==0)return 0;
    return query(root[l-1],root[r],1,lb,val);
}
int A[maxn];
int main()
{

    int nn=read();
    for(int i=1;i<=nn;i++)
        A[i]=read();
    sort(A+1,A+nn+1);
    int n=read();
    for(int i=1;i<=n;i++)
    {
        int x=read();
        int l = 1,r = nn;
        while(l<=r)
        {
            int mid = (l+r)>>1;
            if(A[mid]==x)
            {a[i]=x;break;}
            if(A[mid]<x)l=mid+1;
            else r = mid-1;
        }
        if(a[i]==0)a[i]=inf;
    }
    lb=1;
    for(int i=1;i<=n;i++)
        b[i]=a[i];
    lb=1;
    sort(b+1,b+1+n);
    for(int i=2;i<=n;i++)
        if(b[i]!=b[lb])b[++lb]=b[i];
    node = 0;
    root[0]=build(1,lb);
    for(int i=1;i<=n;i++)
        root[i]=change(root[i-1],1,lb,search(a[i]));
    int m=read();
    for(int i=1;i<=m;i++)
    {
        int n1=read(),n2=read(),n3=read(),n4=read();
        printf("%d\n",get(n3,n4,n2)-get(n3,n4,n1-1));
    }
}
时间: 2024-10-08 10:22:14

CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树的相关文章

求两个对角向上、列索引是偶数的元件和。

//求两个对角向上.列索引是偶数的元件和. #include <stdio.h> int main() { int sum=0; int i,j; int a[5][5]; //为数组赋值 for(i=0;i<5;i++) { for(j=0;j<5;j++) { scanf("%d",&a[i][j]); } } //求两条对角线上行.列下标均为偶数的各元素之和. for(i=0;i<5;i++) { for(j=0;j<5;j++) {

求两条对角线上行、列下标均为偶数的各元素之和。

//求两条对角线上行.列下标均为偶数的各元素之和. #include <stdio.h> int main() { int sum=0; int i,j; int a[5][5]; //为数组赋值 for(i=0;i<5;i++) { for(j=0;j<5;j++) { scanf("%d",&a[i][j]); } } //求两条对角线上行.列下标均为偶数的各元素之和. for(i=0;i<5;i++) { for(j=0;j<5;j++

Python 求两个文本文件以行为单位的交集 并集 差集

Python 求两个文本文件以行为单位的交集 并集 差集,来代码: s1 = set(open('a.txt','r').readlines()) s2 = set(open('b.txt','r').readlines()) print 'ins: %s'%(s1.intersection(s2)) print 'uni: %s'%(s1.union(s2)) print 'dif: %s'%(s1.difference(s2).union(s2.difference(s1))) 原文地址:h

求两个有序整型数组的交集

1. 问题描述 有两个有序的整型数组a和b(没有重复元素),他们的长度分别为lenA和lenB,求出他们的共同元素. 例如:a = 0,1,3,5,7,9,11:b = 2,3,4,7,11: 它们的交集为{3,7,11}. 2. 方法思路 求交集的方法有很多种,但数组的长度会影响算法的效率. 2.1 长度相当时,可采取的算法 2.1.1 二路归并 对于数组a,b分别以i,j从头遍历数组.如果当前位置的a[i]等于b[j],则这两个数是两个数组的一个交集,记录下来并继续遍历:如果a[i]大于b[

java中求两个数组(集合)的交集,并集,差集

对于两个数组 arr1=[1,3,4,5,8,9] arr2=[2,3,7,8,9] 求出交集与并集 test.java 1 import java.util.ArrayList; 2 import java.util.Collections; 3 4 5 public class test1 { 6 public static void main(String[] args) { 7 ArrayList<Integer> tmplist=new ArrayList<Integer>

P2633|主席树+dfs序+树链剖分求lca+离散化

不知道为什么会RE.. 待补 思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的.可以用树链剖分求lca:在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值. 终于能写出这种题了,开心! #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+100; int n,m,e = 1,num,ans=0

哈希(4) - 求两个链表的交集(intersection)以及并集(union)

给定两个链表,求它们的交集以及并集.用于输出的list中的元素顺序可不予考虑. 例子: 输入下面两个链表: list1: 10->15->4->20 list2: 8->4->2->10 输出链表: 交集list: 4->10 并集list: 2->8->20->4->15->10 方法1 (简单方法) 可以参考链表系列中的"链表操作 - 求两个链表的交集(intersection)以及并集(union)" 方法2

写一个方法,求两个数的最大公约数和最小公倍数。

package homework0702; /* * 最大公约数 利用辗转相除法求解两个正整数的最大公约数 在循环中,只要除数不等于0,用较大的数除以较小的数,将小的一个数作为下一轮循环的大数,取得的余数作为下一轮循环较小的数,如此循环直到较小的数值为0,返回较大的数.即为最大公约数. 辗转相除法(欧几里得算法) 定理:两个整数的最大公约数等于其中较小的那个数和两数的相除余数的最大公约数.最大公约数(greatest common divisor)缩写为gcd. 最小公倍数 最小公倍数 = (a

不用【加减乘除】求两个整数之和

首先我们可以分析人们是如何做十进制的加法的,比如是如何得出5+17=22这个结果的.实际上,我们可以分成三步进行: 只做各位相加不进位,此时相加的结果是12(个位数5和7相加不要进位是2,十位数0和1相加结果是1): 做进位,5+7中有进位,进位的值是10;第三步把前面两个结果加起来,12+10的结果是22,刚好5+17=22. 我们一直在想,求两数之和四则运算都不能用,那还能用什么?对数字做运算,除了四则运算之外,也就只剩下位运算了.位运算是针对二进制的,我们就以二进制再来分析一下前面的三步走