【题解】 bzoj1135: [POI2009]Lyz (线段树+霍尔定理)

题面戳我

Solution

  • 二分图是显然的,用二分图匹配显然在这个范围会炸的很惨,我们考虑用霍尔定理。
  • 我们任意选取穿\(l,r\)的号码鞋子的人,那么这些人可以穿的鞋子的范围是\(l,r+d\),这个时候我们可以根据霍尔定理得出满足人人有鞋子穿的时候的式子是
    \(sum[i]\)表示穿\(i\)号鞋子的人数
    \[\sum^r_{i=l} sum[i] \leq (r-l+1+d)*k\]
    我们把这个式子整理下:
    \[\sum^r_{i=l} (sum[i]-k) \leq d*k\]
  • 我们会发现右边是一个常量,那么这个式子就等价与左边的最大值小于等右边即满足,否则不满足
  • 所以我们就只需要找出\(1\rightarrow n\)中最大连续子序列。

New Knowledge

  • 最大连续子序列用线段树来维护,重难点在\(update\)
  • 向上更新
void update(int now,int nl,int nr){
  node[now].sum=node[ls(now)].sum+node[rs(now)].sum;
  node[now].lmax=max(node[ls(now)].lmax,node[ls(now)].sum+node[rs(now)].lmax);
  node[now].rmax=max(node[rs(now)].rmax,node[ls(now)].rmax+node[rs(now)].sum);
  node[now].maxx=max( node[ls(now)].rmax+node[rs(now)].lmax , 
                 max( node[ls(now)].maxx , node[rs(now)].maxx) );return;
}

Code

//It is coded by ning_mew on 7.18
#include<bits/stdc++.h>
#define ls(x) (x*2)
#define rs(x) (x*2+1)
#define LL long long
using namespace std;

const int maxn=2e5+7;

int n,m,d;LL k;
struct Node{LL lmax,rmax,maxx,sum;}node[maxn*4];

void update(int now,int nl,int nr){
  node[now].sum=node[ls(now)].sum+node[rs(now)].sum;
  node[now].lmax=max(node[ls(now)].lmax,node[ls(now)].sum+node[rs(now)].lmax);
  node[now].rmax=max(node[rs(now)].rmax,node[ls(now)].rmax+node[rs(now)].sum);
  node[now].maxx=max( node[ls(now)].rmax+node[rs(now)].lmax , max( node[ls(now)].maxx , node[rs(now)].maxx) );return;
}
void build(int now,int nl,int nr){
  if(nl==nr){node[now].sum=node[now].maxx=node[now].lmax=node[now].rmax=-k;return;}
  int mid=(nl+nr)/2;
  build(ls(now),nl,mid);build(rs(now),mid+1,nr);
  update(now,nl,nr);
}
void add(int now,int nl,int nr,int pl,LL ad){
  if(nl==nr&&nr==pl){
    LL box=node[now].sum+ad; node[now].sum=box;node[now].maxx=box;node[now].lmax=box;node[now].rmax=box; return;
  } if(nr<pl||pl<nl)return;
  int mid=(nl+nr)/2;
  add(ls(now),nl,mid,pl,ad);add(rs(now),mid+1,nr,pl,ad);
  update(now,nl,nr);
}
int main(){
  scanf("%d%d%lld%d",&n,&m,&k,&d);
  build(1,1,n);
  for(int i=1;i<=m;i++){
    int r;LL x;scanf("%d%lld",&r,&x);
    add(1,1,n,r,x);//cout<<node[1].maxx<<endl;
    if(node[1].maxx>d*k)printf("NIE\n");else printf("TAK\n");
  }return 0;
}

博主蒟蒻,随意转载。但必须附上原文链接:http://www.cnblogs.com/Ning-Mew/,否则你会场场比赛暴0!!!

转载于:https://www.cnblogs.com/Ning-Mew/p/9331098.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值