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;
}