HDU 6406 (预处理+rmq+二分)

题意:
给出一个序列,询问会修改序列中的一个数字,然后问从1—n,最大值变化的次数。每次询问之间是独立的。


思路:
首先计算出每个位置开始到最后的最大值变化次数,每个位置的上一个最大值的位置。
通过rmq+二分可以计算出当前位置在当前询问值的情况下,下一个最大值更新的位置在哪里,然后通过预处理的信息前后合并即可。


代码:

#include <algorithm>
#include  <iostream>
#include   <iomanip>
#include   <sstream>
#include   <cstring>
#include   <cstdlib>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <bitset>
#include     <cmath>
#include     <ctime>
#include     <queue>
#include     <stack>
#include      <list>
#include       <map>
#include       <set>
#define X first
#define Y second
#define pb push_back
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define sd(n) scanf("%d",&n)
#define sf(n) scanf("%lf",&n)
#define cout1(x) cout<<x<<endl
#define ALL(x) x.begin(),x.end()
#define sdd(n,m) scanf("%d%d",&n,&m)
#define INS(x) inserter(x,x.begin())
#define mst(a,b) memset(a,b,sizeof(a))
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define cout2(x,y) cout<<x<<" "<<y<<endl
#define qclear(a) while(!a.empty())a.pop()
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define IOS std::ios::sync_with_stdio(false)
#define SRAND srand((unsigned int)(time(0)))
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define cout3(x,y,z) cout<<x<<" "<<y<<" "<<z<<endl

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
using namespace std;

const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const ll mod=998244353;
const int maxn=200005;
const int maxm=300005;

int n,m;
int a[maxn];
int d[maxn][32];
void rmqinit(int* a,int len) {
    mst(d,0);
    for(int i=1; i<=len; i++)
        d[i][0]=a[i];
    for(int j=1; (1<<j)<=len+1; j++) {
        for(int i=1; i+(1<<j)-1<=len; i++) {
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
        }
    }
}
int rmq(int l,int r) {
    int k=0;
    while((1<<(k+1))<=r-l+1)
        k++;
    return max(d[l][k],d[r-(1<<k)+1][k]);
}

int getpos(int pos,int val) {
    int l,r,ans;
    l=pos+1;
    r=n+1;
    ans=r;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(rmq(pos+1,mid)>val) {
            ans=mid;
            r=mid-1;
        } else {
            l=mid+1;
        }
    }
    return ans;
}
int dp[maxn];
bool sel[maxn];
int pre[maxn];
int precnt[maxn];
int allcnt;
void init() {
    dp[n+1]=0;
    for(int i=n; i>=1; i--) {
        int pos=getpos(i,a[i]);
        dp[i]=dp[pos]+1;
    }
    sel[1]=1;
    pre[1]=-1;
    precnt[1]=1;
    int lst=1;
    int lstval=a[1];
    int cnt=1;
    for(int i=2; i<=n; i++) {
        sel[i]=0;
        pre[i]=lst;
        precnt[i]=cnt;
        if(a[i]>lstval) {
            lst=i;
            lstval=a[i];
            sel[i]=1;
            precnt[i]=++cnt;
        }
    }
    allcnt=cnt;
}
void solve() {
    int t;
    sd(t);
    while(t--) {
        sdd(n,m);
        for(int i=1; i<=n; i++)
            sd(a[i]);
        rmqinit(a,n);
        init();
        for(int i=0; i<m; i++) {
            int pos,val;
            sdd(pos,val);
            int ans=0;
            if(sel[pos]) {
                if(pos==0) {
                    ans=1+dp[getpos(pos,val)];
                } else {
                    if(val>a[pre[pos]]) {
                        ans=precnt[pos]+dp[getpos(pos,val)];
                    } else {
                        ans=precnt[pre[pos]]+dp[getpos(pos,a[pre[pos]])];
                    }
                }
            } else {
                if(val>a[pre[pos]]) {
                    ans=precnt[pre[pos]]+1+dp[getpos(pos,val)];
                } else {
                    ans=allcnt;
                }
            }
            printf("%d\n",ans);
        }
    }
    return ;
}
int main() {
#ifdef LOCAL
    freopen("j.in","r",stdin);
    freopen("out.txt","w",stdout);
#else
    //    freopen("","r",stdin);
    //    freopen("","w",stdout);
#endif
    solve();
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值