weinan030416

导航

选数异或(用线段树查询区间最值)

问题描述

给定一个长度为 n 的数列 �1,�2,⋯,��A1,A2,,An 和一个非负整数 x, 给定 m 次查 询, 每次询问能否从某个区间 [�,�][l,r] 中选择两个数使得他们的异或等于 x 。

输入格式

输入的第一行包含三个整数 �,�,�n,m,x 。

第二行包含 n 个整数 �1,�2,⋯,��A1,A2,,An 。

接下来 m 行,每行包含两个整数 ��,��li,ri 表示询问区间 [��,��][li,ri] 。

输出格式

对于每个询问, 如果该区间内存在两个数的异或为 x 则输出 yes, 否则输出 no。

样例输入

4 4 1
1 2 3 4
1 4
1 2
2 3
3 3

样例输出

yes
no
yes
no

样例说明

显然整个数列中只有 22, 33 的异或为 11。

评测用例规模与约定

对于 2020 的评测用例, 1≤�,�≤1001n,m100;

对于 4040 的评测用例, 1≤�,�≤10001n,m1000;

对于所有评测用例, 1≤�,�≤100000,0≤�<220,1≤��≤��≤�1n,m100000,0x<220,1lirin, 0≤��<2200Ai<220 。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M
 一般查询(最后几组会超时)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int Left[maxn], pos[(1 << 20) + 10];
int a[maxn], n, m, x;

int main()
{
    cin >> n >> m >> x;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        Left[i] = pos[a[i] ^ x];
        pos[a[i]] = i;
    }
    while(m--)
    {
        int l, r;
        cin >> l >> r;
        int t=0;
        for(int i=l;i<=r;i++)
        {
            if(Left[i]>t)
            t=Left[i];
        }
        if(t>= l)
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    
    return 0;
}

线段树查询(转换为区间最值查询问题)  查询区间最大值

注意tree数组下标从0开始存

例子:2 3 2 3

Left 0 1 2 3

tree 3 1 3 0 1 2 3

    3

  1    3

0   1    2   3  

附带输出函数过程

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int tree[maxn << 2];
int Left[maxn], pos[(1 << 20) + 10];
int a[maxn], n, m, x;

//线段树模板
//1 1 n
void build(int o, int l, int r)
{
    if(l == r)
    {
        tree[o] = Left[l];
        cout<<"tree["<<o<<"]"<<"=Left["<<l<<"]"<<endl;
        return;
    }
    int mid = (l + r) >> 1;
    
    cout<<"build("<<(o<<1)<<","<<l<<","<<mid<<")"<<endl;
    build(o << 1, l, mid);
    
    cout<<"build("<<(o<<1|1)<<","<<mid+1<<","<<r<<")"<<endl;
    build(o << 1 | 1, mid + 1, r);
    
    cout<<"tree["<<o<<"]"<<"=max(tree["<<(o<<1)<<"],tree["<<(o<<1|1)<<"])"<<endl;
    tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
    
}
//查询区间[L,R]的最大值
//1 1 n l r
int query(int o, int l, int r, int L, int R)
{
    if(L <= l && r <= R)
    {
        cout<<"return tree["<<o<<"]\n";
        return tree[o];
    }
    int mid = (l + r) >> 1;
    int ans = 0;
    cout<<L<<" "<<mid<<" "<<R<<endl; 
    if(L <= mid)
    {
        ans = max(ans, query(o << 1, l, mid, L, R));
    }
    
    if(R > mid)
    {
        ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));//找最大的left[idx] 
    }
    cout<<"return "<<ans<<endl;
    return ans;
}

int main()
{
    cin >> n >> m >> x;
    for(int i = 1; i <= n; i++) //预处理Left数组
    {
        cin >> a[i];
        Left[i] = pos[a[i] ^ x];
        pos[a[i]] = i;
    }
    
    cout<<"Left\n";
    for(int i=1;i<=8;i++)
    {
        cout<<Left[i]<<" ";
    }
    cout<<endl;
    
    build(1, 1, n);//线段树建树
    while(m--)
    {
        int l, r;
        cin >> l >> r;
        if(query(1, 1, n, l, r) >= l)//查询区间最值
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    cout<<"tree\n";
    for(int i=1;i<=8;i++)
    {
        cout<<tree[i]<<" ";
    }
    return 0;
}

 例题:线段树查询区间最大值

查询数组下标为i+1到j+1的最大值

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int tree[maxn << 2];
int Left[maxn], pos[(1 << 20) + 10];
int a[maxn], n, m, x;

//线段树模板
void build(int o, int l, int r)
{
    if(l == r)
    {
        tree[o] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
}
//查询区间[L,R]的最大值
int query(int o, int l, int r, int L, int R)
{
    if(L <= l && r <= R)return tree[o];
    int mid = (l + r) >> 1;
    int ans = 0;
    if(L <= mid)ans = max(ans, query(o << 1, l, mid, L, R));
    if(R > mid)ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));
    return ans;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);//线段树建树
    cout<<"tree"<<endl;
//    for(int i=1;i<2*n;i++)
//    cout<<tree[i]<<" ";
//    cout<<endl;
    while(m--)
    {
        int l, r;
        cin >> l >> r;
        cout<<query(1,1,n,l,r)<<endl;//输出查询到的最大值 
    }
    return 0;
}

查询最小值

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int tree[maxn << 2];
int a[maxn], n,m;

//线段树模板
void build(int o, int l, int r)
{
    if(l == r)
    {
        tree[o] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    tree[o] = min(tree[o << 1], tree[o << 1 | 1]);
}
//查询区间[L,R]的最小值
int query(int o, int l, int r, int L, int R)
{
    if(L <= l && r <= R)return tree[o];
    int mid = (l + r) >> 1;
    int ans = 999999;//查询最小值 
    if(L <= mid)ans = min(ans, query(o << 1, l, mid, L, R));
    if(R > mid)ans = min(ans, query(o << 1 | 1, mid + 1, r, L, R));
    return ans;
}

int main()
{
    cin >> n>>m;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);//线段树建树
//    cout<<"tree"<<endl;
//    for(int i=1;i<2*n;i++)
//    cout<<tree[i]<<" ";
//    cout<<endl;
    while(m--)
    {
        int l, r;
        cin >> l >> r;
        cout<<query(1,1,n,l,r)<<endl;//输出查询到的最小值 
    }
    return 0;
}

 

 

posted on 2023-01-25 10:54  楠030416  阅读(139)  评论(0编辑  收藏  举报