HDU 5649 DZY Loves Sorting (二分 + 线段树)

32 篇文章 0 订阅
27 篇文章 0 订阅

题意:

给你n 个数(1~n的排列), m 个操作, 

操作1: 将指定区间 升序排序

操作2: 将指定区间降序排列。

最后问你某一个的位置的数是多少?

思路:

神题~~~

没想到这能二分去做。。


直接二分那个数是啥。 然后模拟整个操作。

将比二分的值小的赋为0, 大的赋为1,  

然后就是模拟操作

对于升序排序, 直接看看这个区间有多少个0, 多少个1,(线段树维护0的个数即可。)

将前面赋值0 , 后面赋值1即可。

降序同理。

只要看最后那个位置是0 还是1 还是答案即可。

这样 这个问题转换成了  二分 + 线段树区间赋值。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;
int n, m, K;
int a[maxn];
struct node{

    int op;
    int l,r;
    void read(){
        scanf("%d%d%d",&op ,&l, &r);
    }
}p[maxn];


int b[maxn];

struct neode{
    int l,r;
    int setv;
    int sum;
}nod[maxn<<2];

void pushup(int o){
    nod[o].sum = nod[o<<1].sum + nod[o<<1|1].sum;
}

void pushdown(int o){
    if (nod[o].setv != -1){
        int lson = o << 1;
        int rson = o << 1 | 1;
        nod[lson].setv = nod[rson].setv = nod[o].setv;
        if (nod[o].setv == 0){
            nod[lson].sum = nod[lson].r - nod[lson].l + 1;
            nod[rson].sum = nod[rson].r - nod[rson].l + 1;
        }
        else {
            nod[lson].sum = 0;
            nod[rson].sum = 0;
        }
        nod[o].setv = -1;
    }
}
void build(int l,int r,int o){
    nod[o].l = l;
    nod[o].r = r;
    nod[o].setv = -1;
    if (l == r){
        nod[o].sum = (b[l] == 0 ? 1 : 0);
        return ;
    }
    int m = l + r >> 1;
    build(l, m, o<<1);
    build(m+1, r, o<<1|1);
    pushup(o);
}


void update(int L,int R,int c, int l,int r,int o){
    if (L > R) return ;
    if (L <= l && r <= R){
        nod[o].setv = c;
        if (c == 0){
            nod[o].sum = r - l + 1;
        }
        else {
            nod[o].sum = 0;
        }
        return;
    }
    pushdown(o);
    int m = l + r >> 1;
    if (m >= L){
        update(L,R, c, l, m, o<<1);

    }
    if (m < R){
        update(L, R, c, m+1, r, o<<1|1);

    }
    pushup(o);
}
int query(int pos,int l,int r,int o){
    if (l == r){
        if (nod[o].setv != -1) return nod[o].setv;
        return nod[o].sum == 0;
    }

    pushdown(o);
    int m = l + r >> 1;

    if (m >= pos){
        return query(pos, l, m ,o<<1);
    }
    else {
        return query(pos, m+1, r, o<<1|1);
    }
}



int Query(int L,int R,int l,int r,int o){

    if (L <= l && r <= R){

        return nod[o].sum;
    }
    int m = l + r >> 1;
    int ans = 0;
    pushdown(o);
    if (m >= L){
        ans += Query(L,R,l, m, o<<1);
    }
    if (m < R){
        ans += Query(L, R, m+1, r, o<<1|1);
    }
    return ans;
}

int pos;
void deal(int mid){


    for (int i = 1; i <= n; ++i){
        if (a[i] == mid) pos = i;


        if (a[i] < mid) b[i] = 0;
        else if (a[i] > mid) b[i] = 1;
        else b[i] = mid;
    }

    build(1, n, 1);


    for (int i = 0; i < m; ++i){
        if (p[i].op == 0){
            int zero = Query(p[i].l, p[i].r, 1, n, 1);
            if (pos >= p[i].l && pos <= p[i].r){
                update(p[i].l, p[i].l + zero - 1, 0, 1, n, 1);
                update(p[i].l + zero, p[i].l + zero, mid, 1, n, 1);
                pos = p[i].l + zero;
                update(p[i].l + zero + 1, p[i].r, 1, 1, n, 1);
            }
            else {
                update(p[i].l, p[i].l + zero - 1, 0, 1, n, 1);
                update(p[i].l + zero, p[i].r, 1, 1, n, 1);
            }
        }
        else {
            int zero = Query(p[i].l, p[i].r, 1, n, 1);
            if (pos >= p[i].l && pos <= p[i].r){
                update(p[i].r - zero + 1, p[i].r, 0, 1, n, 1);
                update(p[i].r - zero , p[i].r - zero, mid, 1, n, 1);
                update(p[i].l, p[i].r - zero - 1, 1, 1, n, 1);
                pos = p[i].r - zero;
            }
            else {
                update(p[i].r - zero + 1, p[i].r, 0, 1, n, 1);
                update(p[i].l, p[i].r - zero, 1, 1, n, 1);
            }
        }
    }
}

void solve(){

    int l = 1, r = n;
    while(l <= r){
        int m = l + r >> 1;
        deal(m);
        if (pos == K) {
            printf("%d\n", m);
            return;
        }
        int val = query(K, 1, n, 1);

        if (val == 0){
            r = m -1;
        }
        else if (val == 1) l = m + 1;
    }


}

int main(){

    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n, &m);
        for (int i = 1; i <= n; ++i){
            scanf("%d", &a[i]);
        }
        for (int i = 0; i < m; ++i){

            p[i].read();
        }

        scanf("%d",&K);
        solve();
    }
    return 0;
}
/**
1
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

ans = 5;

**/

DZY Loves Sorting

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 547    Accepted Submission(s): 162


Problem Description
DZY has a sequence  a[1..n] . It is a permutation of integers  1n .

Now he wants to perform two types of operations:

0lr : Sort  a[l..r]  in increasing order.

1lr : Sort  a[l..r]  in decreasing order.

After doing all the operations, he will tell you a position  k , and ask you the value of  a[k] .
 

Input
First line contains  t , denoting the number of testcases.

t  testcases follow. For each testcase:

First line contains  n,m m  is the number of operations.

Second line contains  n  space-separated integers  a[1],a[2],,a[n] , the initial sequence. We ensure that it is a permutation of  1n .

Then  m  lines follow. In each line there are three integers  opt,l,r  to indicate an operation.

Last line contains  k .

( 1t50,1n,m100000,1kn,1lrn,opt{0,1} . Sum of  n  in all testcases does not exceed  150000 . Sum of  m  in all testcases does not exceed  150000 )
 

Output
For each testcase, output one line - the value of  a[k]  after performing all  m  operations.
 

Sample Input
  
  
1 6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3
 

Sample Output
  
  
5
Hint
1 6 2 5 3 4 -> [1 2 5 6] 3 4 -> 1 2 [6 5 4 3] -> 1 [2 5 6] 4 3. At last $a[3]=5$.
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   6107  6106  6105  6104  6103 
 

Statistic |  Submit |  Discuss |  Note

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值