BZOJ 4552 [Tjoi2016&Heoi2016]排序 线段树+二分

来源:互联网 发布:d810调焦软件 编辑:程序博客网 时间:2024/06/06 08:58

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1468  Solved: 738
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
位置上的数字。

Input

输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
,1 <= m <= 10^5

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

HINT

Source



二分答案,把当前二分值大的当做1,小的当做0,排序就可以变为区间修改,最后只要看要查询的位置是不是1.


#include <cstdio>#include <iostream>#include <string.h>#include <string> #include <map>#include <queue>#include <deque>#include <vector>#include <set>#include <algorithm>#include <math.h>#include <cmath>#include <stack>#include <iomanip>#define mem0(a) memset(a,0,sizeof(a))#define meminf(a) memset(a,0x3f,sizeof(a))using namespace std;typedef long long ll;typedef long double ld;typedef double db;const int maxn=100005,inf=0x3f3f3f3f;  const ll llinf=0x3f3f3f3f3f3f3f3f;   const ld pi=acos(-1.0L);int a[maxn],l[maxn],r[maxn],w[maxn];int num,q;struct Tree {int lc,rc,l,r,sum,tag;};Tree tree[4*maxn];void build(int now,int l,int r,int c) {tree[now].l=l;tree[now].r=r;tree[now].tag=-1;if (l!=r) {num++;tree[now].lc=num;build(num,l,(l+r)/2,c);num++;tree[now].rc=num;build(num,(l+r)/2+1,r,c);tree[now].sum=tree[tree[now].lc].sum+tree[tree[now].rc].sum;} else tree[now].sum=a[l]>=c?1:0;}void pushdown(int now) {if (tree[now].tag==-1) return;int l=tree[now].lc,r=tree[now].rc;tree[l].tag=tree[now].tag;tree[r].tag=tree[now].tag;tree[l].sum=tree[now].tag*(tree[l].r-tree[l].l+1);tree[r].sum=tree[now].tag*(tree[r].r-tree[r].l+1);tree[now].tag=-1;}void update (int now,int l,int r,int c) {//cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].sum << ' ' << tree[now].tag << endl;if (tree[now].l>=l&&tree[now].r<=r) {tree[now].sum=c*(tree[now].r-tree[now].l+1);tree[now].tag=c; } else {pushdown(now);if (l<=(tree[now].l+tree[now].r)/2)     update(tree[now].lc,l,r,c);if (r>(tree[now].l+tree[now].r)/2)    update(tree[now].rc,l,r,c);tree[now].sum=tree[tree[now].lc].sum+tree[tree[now].rc].sum;}//cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].sum << ' ' << tree[now].tag << endl;}int findsum(int now,int l,int r) {//cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].sum << ' ' << tree[now].tag << endl;pushdown(now);if (tree[now].l>=l&&tree[now].r<=r) {return tree[now].sum;} else {int f=0;if (l<=(tree[now].l+tree[now].r)/2)     f=findsum(tree[now].lc,l,r);if (r>(tree[now].l+tree[now].r)/2)    f+=findsum(tree[now].rc,l,r);return f;}}bool check(int n,int m,int mid) {int i,sum;num=1;build(1,1,n,mid);for (i=1;i<=m;i++) {sum=findsum(1,l[i],r[i]);//cout << '\n';if (sum>0) {if (w[i]) update(1,l[i],l[i]+sum-1,1); elseupdate(1,r[i]-sum+1,r[i],1);} //cout << '\n';if (sum!=r[i]-l[i]+1) {if (!w[i]) update(1,l[i],r[i]-sum,0); elseupdate(1,l[i]+sum,r[i],0);}//cout << '\n';}return findsum(1,q,q);}int main() {int n,m,i,j,pos;scanf("%d%d",&n,&m);for (i=1;i<=n;i++) scanf("%d",&a[i]);for (i=1;i<=m;i++) {scanf("%d%d%d",&w[i],&l[i],&r[i]);}int L,R,mid,ans;L=1;R=n;scanf("%d",&q);while (L<=R) {mid=(L+R)/2;if (check(n,m,mid)) ans=mid,L=mid+1; else R=mid-1;}printf("%d\n",ans);return 0;}


原创粉丝点击