codeforces 264E Roadside Trees

/*

看完题目:靠,这什么玩意儿?能做?

看完数据范围:靠,似乎还可作!

*/


注意到hi<=10,xi<=10,保证任何时刻高度两两不同,于是我们踏上了暴力之路。。。。


我们需要维护的是数组的最长上升序列。

dp[i]表示开头为i的最长上升序列

操作1      对于新增的i,一定是在其后的高度大于hi的树才能转移,而受到i影响的一定是i之前的高度小于hi的。维护一个线段树,以x为下标,dp为权值,支持区间求最大值。我们将高度大于10的全部树的dp全部放进去,小于10的由于总数不会超过10个,直接暴力即可。

操作2      找到第x个树之后(我用的是树状数组),乱搞啦!在维护一颗线段树,以高度为下标,dp为权值,维护除前10棵树的最大值。利用者棵线段树+暴力重新计算前10棵树的dp

/*不要问我复杂度,我自己也不会算了。。。。*/


#include <list>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define lowbit(x) ((x)&(-(x)))
int maxx[400005],dp[100005],tr[100005];
int maxx2[800020],ht[100005];
int n,m,M,tim,ans,x,y,xx,typ,i,j;
list <int> c;
list <int>::iterator I,J;

void add(int p,int l,int r,int x){
  if (l==r && l==x) {maxx[p]=dp[x]; return;}
  int mid=(l+r)>>1;
  if (x<=mid) add(p*2+1,l,mid,x);
    else add(p*2+2,mid+1,r,x);
  maxx[p]=max(maxx[p*2+1],maxx[p*2+2]);
}

int query(int p,int l,int r,int x){
  if (l>=x) return maxx[p];
  int mid=(l+r)>>1;
  if (mid<x) return query(p*2+2,mid+1,r,x);
    else return max( query(p*2+1,l,mid,x), query(p*2+2,mid+1,r,x) );
}

int ADD(int x,int flag){
  for (int i=x;i<=n;i+=lowbit(i))
    tr[i]+=flag;
}

int GET(int x){
  int ret=0;
  for (int i=x;i>0;i-=lowbit(i))
    ret+=tr[i];
  return ret;
}

int calc(int x){
  int ret=0;
  for (int l=1,r=n,mid=(l+r)>>1;l<=r;mid=(l+r)>>1){
    if (x<=GET(mid)) ret=mid, r=mid-1;
      else l=mid+1;
  }
  return ret;
}

void add2(int p,int l,int r,int x,bool flag){
  if (l==r && l==ht[x]+m){
    if (flag) maxx2[p]=dp[x];
      else maxx2[p]=0;
    return;
  }
  int mid=(l+r)>>1;
  if (ht[x]+m<=mid) add2(p*2+1,l,mid,x,flag);
    else add2(p*2+2,mid+1,r,x,flag);
  maxx2[p]=max(maxx2[p*2+1],maxx2[p*2+2]);
}

int query2(int p,int l,int r,int x){
  if (l>=x) return maxx2[p];
  int mid=(l+r)>>1;
  if (x>mid) return query2(p*2+2,mid+1,r,x);
    else return max( query2(p*2+1,l,mid,x), query2(p*2+2,mid+1,r,x) );
}

int main(){
  //freopen("264E.in","r",stdin);
  //freopen("264E.out","w",stdout);
  scanf("%d%d",&n,&m);
  M=m+10;
  for (tim=1;tim<=m;tim++){

    for (I=c.begin();I!=c.end();I++)
      if (ht[*I]+tim>10)
        {add(0,1,n+1,*I); c.erase(I); break;}

    scanf("%d",&typ);
    
    if (typ==1){
      scanf("%d",&x);
      scanf("%d",&ht[x]);
      ht[x]-=tim;
      ADD(x, 1);
      c.push_back(x);
      c.sort();
      
      dp[x]=query(0,1,n+1,x+1)+1;
      I=find(c.begin(),c.end(),x);
      for (I++;I!=c.end();I++)
        if (ht[*I]>ht[x])
          dp[x]=max(dp[x],dp[*I]+1);
      
      I=find(c.begin(),c.end(),x);
      if (I!=c.begin())
      for (I--;;I--){
        for (J=I,J++;J!=c.end();J++)
          if (ht[*I]<ht[*J])
            dp[*I]=max(dp[*I],dp[*J]+1);
        if (GET(*I)>10) add2(0,1,M,*I,1);
        if (I==c.begin()) break;
      }
      
      if (GET(n)>10){
        if (GET(x)<=10) add2(0,1,M,calc(11),1);
          else add2(0,1,M,x,1);
      }
      
    } else
    if (typ==2){
      scanf("%d",&y);
      x=calc(y); ADD(x, -1);
      if (GET(n)>=10)
        add2(0,1,M,calc(10),0);
      I=find(c.begin(),c.end(),x);
      dp[x]=0;
      if (I==c.end()) add(0,1,n+1,x);
        else c.erase(I);
      
      //calc it again
      for (i=1;i<y;i++){
        x=calc(i);
        dp[x]=query2(0,1,M,ht[x]+m)+1;
      }
      for (i=y-1;i>0;i--){
        x=calc(i);
        for (j=i+1;j<=10;j++){
          xx=calc(j);
          if (ht[x]<ht[xx])
            dp[x]=max(dp[x],dp[xx]+1);
        }
        if (ht[x]+tim>10)
          add(0,1,n+1,x);
      }
      
    }
    ans=query(0,1,n+1,1);
    for (I=c.begin();I!=c.end();I++)
      if (ans<dp[*I]) ans=dp[*I];
    printf("%d\n",ans);
    
    //for (i=1;i<=tim;i++)
    //  printf("%d ",ht[ calc(i) ]+tim);
    //printf("\n");
    //printf("%d\n",calc(3));
  }
  return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值