P11244
思路
先考虑怎么用
可以证明,将两个序列合并后排序再拆开一定也是两个有序的数组。
所以一开始先把所有数组排序,如果一次询问的数组在之前进行过操作,则这个数组一定有序,否则将原数组备份的数组中的答案输出。
再使用归并排序中的方法可以做到
考虑到两个数组合并时如果拼起来已经有序,则不用操作;如果将两个数组的顺序调换,则每次只用交换两个数组的下标,用一个数组记录下标即可。这两种情况复杂度
由于两个数组进行一次操作后一定可以使数组有一种方法拼起来后有序,最多对一个数组进行
所以至多进行
综上,我们可以用
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000005,Q=5e6+5;
int tmp[2*N],tag[25],p[25];
vector<int>a[25],b[25];
int opp[Q],uu[Q],vv[Q],t[25];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m,T;
cin>>n>>m>>T;
for(int i=1;i<=m;i++)
{
a[i].push_back(0);
b[i].push_back(0);
for(int j=1;j<=n;j++)
{
int x;
cin>>x;
a[i].push_back(x);
b[i].push_back(x);
}
sort(a[i].begin(),a[i].end());
p[i]=i;
}
int op,u,v,last=0,cnt=0;
for(int i=1;i<=T;i++)
{
cin>>opp[i]>>uu[i]>>vv[i];
if(opp[i]==2)
{
t[uu[i]]=1;
last=i;
cnt++;
}
}
if(cnt==1)return 0;
for(int i=1;i<=last;i++)
{
op=opp[i];u=uu[i];v=vv[i];
int &x=p[u];
if(op==1)
{
//if(!t[u]&&!t[v])continue;
int &y=p[v];
if(a[x][n]<=a[y][1])continue;
if(a[y][n]<=a[x][1])
{
swap(x,y);
continue;
}
int l1=1,l2=1;
for(int i=1;i<=n+n;i++)
{
if(l1==n+1)tmp[i]=a[y][l2++];
else if(l2==n+1)tmp[i]=a[x][l1++];
else if(a[x][l1]<a[y][l2])tmp[i]=a[x][l1++];
else tmp[i]=a[y][l2++];
}
for(int i=1;i<=n;i++)
{
a[x][i]=tmp[i];
a[y][i]=tmp[i+n];
}
tag[x]=1;
tag[y]=1;
}
else
{
if(!tag[u])cout<<b[x][v]<<'\n';
else cout<<a[x][v]<<'\n';
}
}
return 0;
}