Codeforces1982 F. Sorting Problem Again(思维+线段树+set,cf2600)

题意:

在这里插入图片描述
在这里插入图片描述

解法:

在这里插入图片描述

补充说明:
假设最后的解是[l,r],[1,l-1]以及[r+1,n]一定是有序的.
想办法找到这个l-1和r+1:
我们可以维护有序的最大前缀和后缀.
对于中间无序的部分,求出mi和ma.
然后用mi筛掉前缀中必须排序的部分,
用ma筛掉后缀中必须排序的部分.
Code:
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define int long long
#define PI pair<int, int>
const int maxm=2e6+5;
const int mod=998244353;
int n;
int a[maxm];
struct STT{
    int mi[maxm<<2];
    int ma[maxm<<2];
    void pushup(int k){
      mi[k]=min(mi[k*2],mi[k*2+1]);
      ma[k]=max(ma[k*2],ma[k*2+1]);
    }
    void update(int x,int val,int l,int r,int k){
      if(l==r){
          mi[k]=ma[k]=val;
          return ;
      }
      int mid=(l+r)/2;
      if(x<=mid)update(x,val,l,mid,k*2);
      else update(x,val,mid+1,r,k*2+1);
      pushup(k);
    }
    int ask(int st,int ed,int f/*是否求最小值*/,int l,int r,int k){
      if(st<=l&&ed>=r){
        return f?mi[k]:ma[k];
      }
      assert(l!=r);
      int mid=(l+r)/2;
      int ans=f?1e18:-1e18;
      if(st<=mid){
        if(f)ans=min(ans,ask(st,ed,f,l,mid,k*2));
        else ans=max(ans,ask(st,ed,f,l,mid,k*2));
      }
      if(ed>mid){
        if(f)ans=min(ans,ask(st,ed,f,mid+1,r,k*2+1));
        else ans=max(ans,ask(st,ed,f,mid+1,r,k*2+1));
      }
      return ans;
    }
    void init(int l,int r,int k){
      mi[k]=1e18;
      ma[k]=1e18;
      if(l==r)return ;
      int mid=(l+r)/2;
      init(l,mid,k*2);
      init(mid+1,r,k*2+1);
    }
}T;
set<int>st;
void query() {
  if(!st.size()){
    cout<<"-1 -1"<<endl;
    return ;
  }
  int lc=*st.begin()-1;
  int rc=*st.rbegin();
  // 答案一定包含[lc,rc]
  // cout<<lc<<' '<<rc<<endl;
  // [1,lc]一定是有序的
  // [rc,n]一定是有序的
  int mi=T.ask(lc,rc,1,1,n,1);
  int ma=T.ask(lc,rc,0,1,n,1);
  // for(int i=1;i<=n;i++){
  //   cout<<T.ask(i,i,0,1,n,1)<<' ';
  // }
  // cout<<endl;
  // cout<<"mi:"<<mi<<' '<<"ma:"<<ma<<endl;
  //
  int L=0;
  int l=1,r=lc-1;
  while(l<=r){
    int mid=(l+r)/2;
    if(a[mid]<=mi){
      L=mid,l=mid+1;
    } else {
      r=mid-1;
    }
  }
  //
  int R=n+1;
  l=rc+1,r=n;
  while(l<=r){
    int mid=(l+r)/2;
    if(a[mid]>=ma){
      R=mid,r=mid-1;
    } else {
      l=mid+1;
    }
  }
  // cout<<"L:"<<L<<' '<<"R:"<<R<<endl;
  L++;
  R--;
  if(L<R){
    cout<<L<<' '<<R<<endl;
  } else {
    cout<<-1<<' '<<-1<<endl;
  }
}
void solve(){
  cin>>n;
  for(int i=1;i<=n;i++)cin>>a[i];
  st.clear();
  for(int i=2;i<=n;i++){
    if(a[i]<a[i-1]){
      st.insert(i);
    }
  }
  T.init(1,n,1);
  for(int i=1;i<=n;i++){
    T.update(i,a[i],1,n,1);
  }
  // for(int i=1;i<=n;i++){
  //   cout<<T.ask(i,i,0,1,n,1)<<' ';
  // }
  // cout<<endl;
  query();
  int q;cin>>q;
  while(q--){
    int pos,x;cin>>pos>>x;
    if(pos-1>=1&&a[pos]<a[pos-1]){
      st.erase(pos);
    }
    if(pos+1<=n&&a[pos+1]<a[pos]){
      st.erase(pos+1);
    }
    a[pos]=x;
    if(pos-1>=1&&a[pos]<a[pos-1]){
      st.insert(pos);
    }
    if(pos+1<=n&&a[pos+1]<a[pos]){
      st.insert(pos+1);
    }
    T.update(pos,x,1,n,1);
    query();
  }
}
signed main() {
#define MULTI_CASE
  ios::sync_with_stdio(0);
  cin.tie(0);
#ifndef ONLINE_JUDGE
  freopen("../in.txt", "r", stdin);
  freopen("../out.txt", "w", stdout);
#endif
#ifdef MULTI_CASE
  int T;
  cin >> T;
  while (T--)
#endif
    solve();
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值