【LOJ2055】【洛谷P2824】排序【线段树】【二分答案】
题目大意:
题目链接:
洛谷:https://www.luogu.org/problem/P2824
LOJ:https://loj.ac/problem/2055#submit_code
给出一个的排列,两个操作:
- :将的数字升序排列
- :将的数字降序排列
给出,求出最终位于数列第位的数字。
思路:
思路!
暴力的复杂度时的,其中排序复杂度,如果可以有效减少排序的复杂度,就可以降低代码复杂度。
我们发现,01序列的排序可以在内完成。以升序排列为例,我们用线段树维护出区间数字1的个数,然后区间修改为1,为0。 .
那么如何把原数列转换成01数列呢?考虑二分答案。
我们在区间内二分答案,每次把大于等于的数字变成1,小于的数字变成0,然后完成所有操作,最终如果在第为上的数字是1,那么最终答案一定大于等于,否则小于。
时间复杂度
代码:
#include <cstdio>
#include <string>
#define reg register
using namespace std;
const int N=100010;
int n,m,opt,l,r,mid,x,y,q,a[N],b[N];
struct Ask
{
int l,r,opt;
}ask[N];
struct Tree
{
int l,r,lazy,sum;
}tree[N*4];
int read()
{
int d=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch))
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
void build(int x)
{
tree[x].lazy=-1; tree[x].sum=0;
if (tree[x].l==tree[x].r)
{
tree[x].sum=a[tree[x].l];
return;
}
int mid=(tree[x].l+tree[x].r)>>1;
tree[x*2].l=tree[x].l;
tree[x*2].r=mid;
tree[x*2+1].l=mid+1;
tree[x*2+1].r=tree[x].r;
build(x*2); build(x*2+1);
tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
}
void pushdown(int x)
{
if (tree[x].lazy!=-1)
{
tree[x*2].lazy=tree[x].lazy;
tree[x*2+1].lazy=tree[x].lazy;
tree[x*2].sum=tree[x].lazy*(tree[x*2].r-tree[x*2].l+1);
tree[x*2+1].sum=tree[x].lazy*(tree[x*2+1].r-tree[x*2+1].l+1);
tree[x].lazy=-1;
}
}
int find(int x,int l,int r)
{
if (l>r) return 0;
if (tree[x].l==l && tree[x].r==r)
return tree[x].sum;
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if (r<=mid) return find(x*2,l,r);
if (l>mid) return find(x*2+1,l,r);
return find(x*2,l,mid)+find(x*2+1,mid+1,r);
}
void change(int x,int l,int r,int val)
{
if (l>r) return;
if (tree[x].l==l && tree[x].r==r)
{
tree[x].sum=val*(tree[x].r-tree[x].l+1);
tree[x].lazy=val;
return;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if (r<=mid) change(x*2,l,r,val);
else if (l>mid) change(x*2+1,l,r,val);
else change(x*2,l,mid,val),change(x*2+1,mid+1,r,val);
tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
}
int main()
{
n=read(); m=read();
for (reg int i=1;i<=n;i++)
b[i]=read();
for (reg int i=1;i<=m;i++)
ask[i].opt=read(),ask[i].l=read(),ask[i].r=read();
q=read();
l=1; r=n;
while (l<=r)
{
mid=(l+r)>>1;
for (reg int i=1;i<=n;i++)
if (b[i]<mid) a[i]=0;
else a[i]=1;
tree[1].l=1; tree[1].r=n;
build(1);
for (reg int i=1;i<=m;i++)
{
int sum=find(1,ask[i].l,ask[i].r);
if (!ask[i].opt)
{
change(1,ask[i].l,ask[i].r-sum,0);
change(1,ask[i].r-sum+1,ask[i].r,1);
}
else
{
change(1,ask[i].l,ask[i].l+sum-1,1);
change(1,ask[i].l+sum,ask[i].r,0);
}
}
if (find(1,q,q)==1) l=mid+1;
else r=mid-1;
}
printf("%d\n",l-1);
return 0;
}