背景:
补坑…
题目传送门:
https://www.luogu.org/problemnew/show/P2824
题意:
n
n
n个数,两种操作:
0
0
0:将
[
l
,
r
]
[l,r]
[l,r]升序排序;
1
1
1:将
[
l
,
r
]
[l,r]
[l,r]降序排序。求最后在第
q
q
q个位置上的数。
思路:
比较妙的一道题。
根据数据范围可以知道是一个
Θ
(
n
l
o
g
n
)
\Theta(nlogn)
Θ(nlogn)带大常数,
Θ
(
n
l
o
g
2
n
)
\Theta(nlog^2n)
Θ(nlog2n),
Θ
(
n
l
o
g
3
n
)
\Theta(nlog^3n)
Θ(nlog3n),
Θ
(
n
n
)
\Theta(n\sqrt{n})
Θ(nn)的做法。
好像不会。
考虑将问题转化为
01
01
01序列的问题。不妨考虑二分
m
i
d
mid
mid。将不大于
m
i
d
mid
mid的看做
1
1
1,大于
m
i
d
mid
mid的数看做
0
0
0,此时用线段树来解决这样的问题就容易多了。
考虑
0
0
0操作。我们可以求出区间
1
1
1的个数,将这个区间后面这么多的数赋值为
1
1
1,前面赋值为
0
0
0。
1
1
1操作同理。
最后再判一下第
q
q
q个数是否为
1
1
1,若是
1
1
1,就可以二分更小的数(因为将不大于
m
i
d
mid
mid的看做
1
1
1,此时第
q
q
q个位置可能小于
m
i
d
mid
mid)。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,q,len,ans;
int d[100010];
struct node1{int l,r,lc,rc,n,d,lazy;} tr[200010];
struct node2{int x,y,z;} a[100010];
void init()
{
len=0;
memset(tr,0,sizeof(tr));
}
void build(int l,int r)
{
int now=++len;
tr[now]=(node1){l,r,-1,-1,r-l+1,0,-1};
if(l<r)
{
int mid=(l+r)>>1;
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void update(int now)
{
if(tr[now].lazy!=-1)
{
int lc=tr[now].lc,rc=tr[now].rc;
if(lc!=-1) tr[lc].lazy=tr[now].lazy,tr[lc].d=tr[lc].n*tr[now].lazy;
if(rc!=-1) tr[rc].lazy=tr[now].lazy,tr[rc].d=tr[rc].n*tr[now].lazy;
tr[now].lazy=-1;
}
}
void change(int now,int l,int r,int k)
{
update(now);
if(l==tr[now].l&&r==tr[now].r)
{
tr[now].lazy=k;
tr[now].d=tr[now].n*k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) change(lc,l,r,k);
else if(l>mid) change(rc,l,r,k);
else change(lc,l,mid,k),change(rc,mid+1,r,k);
tr[now].d=tr[lc].d+tr[rc].d;
}
int findsum(int now,int l,int r)
{
update(now);
if(l==tr[now].l&&r==tr[now].r) return tr[now].d;
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findsum(lc,l,r);
else if(l>mid) return findsum(rc,l,r);
else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
}
void work(int op)
{
build(1,n);
for(int i=1;i<=n;i++)
if(d[i]<=op) change(1,i,i,1);
for(int i=1;i<=m;i++)
{
int x=a[i].x,y=a[i].y,z=a[i].z,tot=findsum(1,x,y);
if(!tot||tot==y-x+1) continue;
if(!z)
{
change(1,x,x+tot-1,1);
change(1,x+tot-1+1,y,0);
}
else
{
change(1,x,y-tot+1-1,0);
change(1,y-tot+1,y,1);
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&d[i]);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a[i].z,&a[i].x,&a[i].y);
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
}
scanf("%d",&q);
int l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
init();
work(mid);
mid=(l+r)>>1;
if(findsum(1,q,q)) ans=mid,r=mid-1; else l=mid+1;
}
printf("%d",ans);
}