题解:裸上一棵线段树就可以解决了。
用线段树维护一个一开始全为0的数列,每次修改操作先记录下来,把这次修改操作所影响到位置对应的区间修改为这次操作的序数(也就是第几次操作)。查询的时候,先查询这个区间里面的对应位置,看看最后影响到这个数字的操作是哪一个,找到那次操作的具体内容,对比一下就可以得到答案了。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#define lson (nd<<1)
#define rson (nd<<1|1)
using namespace std;
struct node{
int num;
bool flag;
}t[1000010];
void pd(int nd)
{if(!t[nd].flag) return ;t[lson].num=t[rson].num=t[nd].num;t[lson].flag=t[rson].flag=1;t[nd].flag=0;}
void build(int L,int R,int nd)
{
t[nd].num=-1;
if(L==R) return ;
int mid=(L+R)>>1;
build(L,mid,lson);build(mid+1,R,rson);
}
int find(int L,int R,int nd,int x)
{
pd(nd);
if(L==R) return t[nd].num;
int mid=(L+R)>>1;
if(x<=mid) return find(L,mid,lson,x);
return find(mid+1,R,rson,x);
}
void modify(int L,int R,int l,int r,int nd,int v)
{
pd(nd);
if(l<=L&&R<=r){t[nd].num=v;t[nd].flag=1;return ;}
int mid=(L+R)>>1;
if(l<=mid) modify(L,mid,l,r,lson,v);
if(r>mid) modify(mid+1,R,l,r,rson,v);
}
int n,m,cnt;
int a[200010],b[200010],q[200010][3];
int main()
{
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(x==1)
{
cnt++;
scanf("%d%d%d",&q[cnt][0],&q[cnt][2],&q[cnt][1]);
modify(1,n,q[cnt][2],q[cnt][2]+q[cnt][1]-1,1,cnt);
}
else
{
scanf("%d",&y);
x=find(1,n,1,y);
if(x<=0) printf("%d\n",b[y]);
else printf("%d\n",a[q[x][0]+y-q[x][2]]);
}
}
return 0;
}