[bzoj4552][Tjoi2016&Heoi2016]排序-二分+线段树

本文介绍了一种使用线段树和二分搜索解决特定问题的方法:在一个给定的排列上执行多次升序或降序操作后找到指定位置的元素值。通过维护线段树来高效地更新和查询区间内的元素状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树而已;
参考:http://blog.youkuaiyun.com/werkeytom_ftd/article/details/51366237
http://www.cnblogs.com/gengchen/p/6613566.html

题目大意

有一个n的排列,进行m次操作,每次操作是将一个区间升序或降序排序。
请你输出m次操作后第p个位置的值。
二分答案



我们二分答案x,然后就是判断a[p]>=x?
#include <cstdio>
#define init int l = t[k].l, r = t[k].r, mid = (l + r) >> 1
const int maxn = 1e5 + 1e2;
int n, m, a[maxn], lambda, q;
struct seg {
  int l, r, val, cov;
} t[maxn << 4];
struct op {
  int a, b, c;
} o[maxn];
void update(int k) { t[k].val = t[k << 1].val + t[k << 1 | 1].val; }
void build(int k, int l, int r) {
  t[k].l = l, t[k].r = r, t[k].cov = -1;
  if (l == r) {
    t[k].val = a[l] > lambda;
    return;
  }
  int mid = (l + r) >> 1;
  build(k << 1, l, mid);
  build(k << 1 | 1, mid + 1, r);
  update(k);
}
void pushdown(int k) {
  if (t[k].cov != -1) {
    t[k << 1].cov = t[k].cov;
    t[k << 1 | 1].cov = t[k].cov;
    t[k << 1].val = (t[k << 1].r - t[k << 1].l + 1) * (t[k].cov);
    t[k << 1 | 1].val = (t[k << 1 | 1].r - t[k << 1 | 1].l + 1) * (t[k].cov);
    t[k].cov = -1;
  }
  if (t[k].l < t[k].r)
    update(k);
}
int query(int k, int x, int y) {
  init;
  pushdown(k);
  if (x <= l && r <= y)
    return t[k].val;
  int ans = 0;
  if (x <= mid)
    ans += query(k << 1, x, y);
  if (y > mid)
    ans += query(k << 1 | 1, x, y);
  return ans;
}
void modify(int k, int x, int y, int val) {
  init;
  pushdown(k);
  if (x <= l && r <= y) {
    t[k].val = (r - l + 1) * val;
    t[k].cov = val;
    return;
  }
  if (x <= mid)
    modify(k << 1, x, y, val);
  if (y > mid)
    modify(k << 1 | 1, x, y, val);
  update(k);
}
bool check(int x) {
  lambda = x;
  build(1, 1, n);
  for (int i = 1; i <= m; i++) {
    int opt = o[i].a, x = o[i].b, y = o[i].c;
    int tmp = query(1, x, y);
    if (opt == 0) {
      modify(1, x, y - tmp, 0);
      modify(1, y - tmp + 1, y, 1);
    } else {
      modify(1, x, x + tmp - 1, 1);
      modify(1, x + tmp, y, 0);
    }
  }
  return !query(1, q, q);
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("input", "r", stdin);
#endif
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; ++i)
    scanf("%d", &a[i]);
  int l = 1, r = n;
  for (int i = 1; i <= m; i++) {
    scanf("%d %d %d", &o[i].a, &o[i].b, &o[i].c);
  }
  scanf("%d", &q);
  while (l < r) {
    int mid = (l + r) >> 1;
    if (check(mid))
      r = mid;
    else
      l = mid + 1;
  }
  printf("%d", r);
}

我的代码又错了..

#include<bits/stdc++.h>

using namespace std;
#define N 100050
#define md ((ll+rr)>>1)
#define ls (i<<1)
#define rs (ls|1)
#define lson ls,ll,md
#define rson rs,md+1,rr
int n,m;
int ans;
int a[N];
int ask[N][3];
int lazy[N*5];
int sum[N*5];
int p;
void ch(){
    for(int i=1;i<=n;++i)printf("%d",sum[i]);puts("");
}
void down(int i,int ll,int rr){
    if(lazy[i]==-1)return;
    sum[ls]=(md-ll+1)*lazy[i];
    sum[rs]=(rr-md)*lazy[i];
    lazy[ls]=lazy[rs]=lazy[i];
    lazy[i]=-1;
}
int query(int i,int ll,int rr,int l,int r){
    if(l==ll&&rr==r){
        return sum[i];
    }
    down(i,ll,rr);
    if(r<=md)return query(ls,ll,md,l,r);
    else if(l>md)return query(rs,md+1,rr,l,r);
    else{
        return query(lson,l,md)+query(rson,md+1,r);
    }
}
void update(int i,int ll,int rr,int l,int r,int val){
    if(l==ll&&rr==r){
        lazy[i]=val;
        sum[i]=(rr-ll+1)*val;
        return ;
    }
    down(i,ll,rr);
    //cout<<md<<endl;
    //printf("%d %d\n %d %d\n",ll,rr,l,r);
    if(r<=md)update(lson,l,r,val);
    else if(l>md)update(rson,l,r,val);
    else update(lson,l,md,val),update(rson,md+1,r,val);
    sum[i]=sum[ls]+sum[rs];
}
bool ok(int mid){
    memset(lazy,-1,sizeof(lazy));
    //ch();
    for(int i=1;i<=n;++i)
        if(a[i]<mid)update(1,1,n,i,i,0);
        else update(1,1,n,i,i,1);
    for(int i=1;i<=m;++i){
        int t=query(1,1,n,ask[i][1],ask[i][2]);
        if(ask[i][0]){
            update(1,1,n,ask[i][1],ask[i][1]+t-1,1);
            update(1,1,n,ask[i][1]+t-1,ask[i][2],0);
        }
        else{
            update(1,1,n,ask[i][1],ask[i][2]-t+1,0);
            update(1,1,n,ask[i][2]-t+1,ask[i][2],1);
        }
    }
    return !query(1,1,n,p,p);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&ask[i][0],&ask[i][1],&ask[i][2]);
    }
    int l=0,r=n;
    scanf("%d",&p);
    while(l<=r){
        int mid=(l+r)>>1;
        if(ok(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值