HDU 6703 array 2019CCPC网络选拔赛 1002 (线段树/权值线段树/主席树+set)

array

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1356    Accepted Submission(s): 522


 

Problem Description

You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of the array is **unique**.

Moreover, there are m instructions.

Each instruction is in one of the following two formats:

1. (1,pos),indicating to change the value of apos to apos+10,000,000;
2. (2,r,k),indicating to ask the minimum value which is **not equal** to any ai ( 1≤i≤r ) and **not less ** than k.

Please print all results of the instructions in format 2.

 

 

 

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, there are two integers n(1≤n≤100,000),m(1≤m≤100,000) in the first line, denoting the size of array a and the number of instructions.

In the second line, there are n distinct integers a1,a2,...,an (∀i∈[1,n],1≤ai≤n),denoting the array.
For the following m lines, each line is of format (1,t1) or (2,t2,t3).
The parameters of each instruction are generated by such way :

For instructions in format 1 , we defined pos=t1⊕LastAns . (It is promised that 1≤pos≤n)

For instructions in format 2 , we defined r=t2⊕LastAns,k=t3⊕LastAns. (It is promised that 1≤r≤n,1≤k≤n )

(Note that ⊕ means the bitwise XOR operator. )

Before the first instruction of each test case, LastAns is equal to 0 .After each instruction in format 2, LastAns will be changed to the result of that instruction.

(∑n≤510,000,∑m≤510,000 )

 

 

Output

For each instruction in format 2, output the answer in one line.

 

 

Sample Input

 

3 5 9 4 3 1 2 5 2 1 1 2 2 2 2 6 7 2 1 3 2 6 3 2 0 4 1 5 2 3 7 2 4 3 10 6 1 2 4 6 3 5 9 10 7 8 2 7 2 1 2 2 0 5 2 11 10 1 3 2 3 2 10 10 9 7 5 3 4 10 6 2 1 8 1 10 2 8 9 1 12 2 15 15 1 12 2 1 3 1 9 1 12 2 2 2 1 9

 

 

Sample Output

 

1 5 2 2 5 6 1 6 7 3 11 10 11 4 8 11

Hint

note: After the generation procedure ,the instructions of the first test case are : 2 1 1, in format 2 and r=1 , k=1 2 3 3, in format 2 and r=3 , k=3 2 3 2, in format 2 and r=3 , k=2 2 3 1, in format 2 and r=3 , k=1 2 4 1, in format 2 and r=4 , k=1 2 5 1, in format 2 and r=5 , k=1 1 3 , in format 1 and pos=3 2 5 1, in format 2 and r=5 , k=1 2 5 2, in format 2 and r=5 , k=2 the instructions of the second test case are : 2 7 2, in format 2 and r=7 , k=2 1 5 , in format 1 and pos=5 2 7 2, in format 2 and r=7 , k=2 2 8 9, in format 2 and r=8 , k=9 1 8 , in format 1 and pos=8 2 8 9, in format 2 and r=8 , k=9 the instructions of the third test case are : 1 10 , in format 1 and pos=10 2 8 9 , in format 2 and r=8 , k=9 1 7 , in format 1 and pos=7 2 4 4 , in format 2 and r=4 , k=4 1 8 , in format 1 and pos=8 2 5 7 , in format 2 and r=5 , k=7 1 1 , in format 1 and pos=1 1 4 , in format 1 and pos=4 2 10 10, in format 2 and r=10 , k=10 1 2 , in format 1 and pos=2

 

 

Source

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6724 6723 6722 6721 6720 

 

题意:

给你n哥数,实现操作两种,

1 x:给第x个数加上1e7;

2 x y:查询最小的且>=y的且不在区间[1,x]里出现过的数。

分析:

线段树

因为一开始数字是属于[1,n]的,所以对于询问操作的答案最大为n+1,即第一个操作没有用了,相当于删除了这个数。我们开一个大小为[1,n+1]线段树,节点保值值的位置pos的最大值。

  • 对于第二个操作相当于寻找[y,n+1]区间里且位置大于x的最小的数,这里需要一个剪枝我们优先找左子树的,因为左子树的值肯定比右子树少
  • 对于第一个操作,我们直接把该值位置赋值上n+1即可。

主席树+set

答案来自两个方向:

  • 主席树a[r+1,n]里找>=k的最小值。
  • set里找>=k的最小值(对set进行二分查找)

权值线段树

 

#include
using namespace std;
typedef long long ll;
const int N=500005;

int a[N],pos[N];
int n,m;

struct node  //线段树
{
    int l,r;
    int dat;
} tree[N*4];
void PushUp(int x)   //线段树维护结点信息
{
    tree[x].dat=max(tree[x<<1].dat,tree[x<<1|1].dat);
}
void build(int x,int l,int r)  //线段树建树
{
    tree[x].l=l;
    tree[x].r=r;
    if (l==r)   //叶子节点
    {
        tree[x].dat=pos[l];
        return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    PushUp(x);
}
int ans;
void findd(int x,int R)
{
	
    if(tree[x<<1].dat>R)
	 {
	 	findd(x<<1,R);
	 }
	 else if(tree[x<<1|1].dat>R)
	 {
	 	findd(x<<1|1,R);
	 }
	 if(tree[x].l==tree[x].r&&tree[x].dat>R)
	{
		ans=min(ans, tree[x].l);
	}
}

void query(int x,int l,int r,int R)  //线段树区间查询
{
	
    if (l<=tree[x].l&&r>=tree[x].r)
	{
		
		 findd(x,R);  //找到
		 return ;
	}
        

    int mid=(tree[x].l+tree[x].r)>>1;

    if (l<=mid)
       query(x<<1,l,r,R);
    if (r>mid)
        query(x<<1|1,l,r,R);
   
}

void update(int x,int y)  //线段树单点修改
{
    if (tree[x].l==tree[x].r)
    {
        tree[x].dat =n+1;
        return ;
    }
    int mid=(tree[x].l+tree[x].r)>>1;
    if (y<=mid)
        update(x<<1,y);
    else
        update(x<<1|1,y);
    PushUp(x);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            pos[a[i]]=i;
        }
        pos[n+1]=n+1;
        build(1,1,n+1);
        ans=0;
        for(int i=1; i<=m; i++)
        {
            int op,x,k;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&x);
                x^=ans;
                update(1,a[x]);
            }
            else
            {
                scanf("%d%d",&x,&k);
                x^=ans;
                k^=ans;
				ans=1e9;
                query(1,k,n+1,x);
                printf("%d\n",ans);
            }
        }




    }
    return 0;
}

主席树+set

#include 
using namespace std;
typedef long long LL;

const int maxn=1e5+7;
int cnt,root[maxn],a[maxn];
//cnt和root:主席树的总点数和每一个根
struct node
{
    int l,r,sum;
} T[maxn*40];
///单点修改
int build(int l,int r)
{
	int cur=++cnt;
	T[cur].sum=0;
	if(l==r) return cur;
	int mid=l+r>>1;
	build(l,mid);
	build(mid+1,r);
	return cur;
}

void update(int l,int r,int &x,int y,int pos)
{
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(mid>=pos)
        update(l,mid,T[x].l,T[y].l,pos);
    else
        update(mid+1,r,T[x].r,T[y].r,pos);
	
	
	
}
///查询区间(x,y)第k小,使用v[query(1,n,root[x-1],root[y],mid)-1]
/*int query(int l,int r,int x,int y,int k)
{
    if(l==r)
        return l;
    int mid=(l+r)/2;
    int sum=T[T[y].l].sum-T[T[x].l].sum;
    if(sum>=k)
        return query(l,mid,T[x].l,T[y].l,k);
    else
        return query(mid+1,r,T[x].r,T[y].r,k-sum);
} */   
///查询区间(x,y)>=k的最小值 query_min(root[x],root[y],1,n,k) 
int query_min(int lrot,int rrot,int l,int r,int k)
{
	if(l==r)
	{
		if(T[rrot].sum-T[lrot].sum>0)
			return l;
		else 
			return 1e9;
	}
	int mid=(l+r)>>1;
	if(k<=mid)
	{
		int ans=1e9;
		if(k<=l)//这里相当于一个剪枝,在小于l的时候,如果左子树有符合条件的就进入左子树,否则再进入右子树。
		{
			if(T[T[rrot].l].sum-T[T[lrot].l].sum>0) ans=min(ans,query_min(T[lrot].l,T[rrot].l,l,mid,k));
			else if(T[T[rrot].r].sum-T[T[lrot].r].sum>0) ans=min(ans,query_min(T[lrot].r,T[rrot].r,mid+1,r,k));
			return ans;
		}
		if(T[T[rrot].l].sum-T[T[lrot].l].sum>0) //k在l到mid之间的时候,左右子树都有可能涉及,就左右都看一遍寻找最优解
		ans=min(ans,query_min(T[lrot].l,T[rrot].l,l,mid,k));
		if(T[T[rrot].r].sum-T[T[lrot].r].sum>0) ans=min(ans,query_min(T[lrot].r,T[rrot].r,mid+1,r,k));
		return ans;
	}
	else
	{
		int ans=1e9;//k大于mid的时候,直接进入右子树,左子树不用找了
		if(T[T[rrot].r].sum-T[T[lrot].r].sum>0) ans=min(ans,query_min(T[lrot].r,T[rrot].r,mid+1,r,k));
		return ans;
	}
}
/*
int two_find(int x,int y,int k)//二分查找第i小的元素小于等于k的最大元素
//即求k是第几小的元素
{
	int l=0,r=y-x+1;
	while(l>1;
		if(v[query(1,n,root[x-1],root[y],mid)-1]<=k)
			l=mid;
		else
			r=mid-1;
	}
	return l;
	
}  */

int n,m;
set s;
set::iterator it;
int main()
{
    int TT;
    scanf("%d",&TT);
    while(TT--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        
        s.clear();
        s.insert(n+1);
        cnt=0;
	    root[0]=build(1,n);
        
        for(int i=1; i<=n; i++)
            update(1,n,root[i],root[i-1],a[i]);
		
        LL ans=0;
        for(int i=1; i<=m; i++)
        {
            int op,x,k;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&x);
                x^=ans;
                s.insert(a[x]);
            }
            else
            {
                scanf("%d%d",&x,&k);
                x^=ans;
                k^=ans;
                if(x!=n)
				ans=min(query_min(root[x],root[n],1,n,k),*s.lower_bound(k));
				else
				ans=*s.lower_bound(k);	
                printf("%d\n",ans);
            }
        }
 
 
 
 
    }
    return 0;
}

 

你可能感兴趣的:(数据结构--线段树,好题,比赛题解,数据结构——主席树,模板)