BZOJ1135: [POI2009]Lyz

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1135

线段树+hall定理。。

设当前穿i号鞋子的人数是a[i],那么我们要保证∑a[i]≤(r-l+1+d)*k,让a[i]-=k,就变成了∑a[i]≤d*k

然后要让任何一段区间都满足这个条件,那么求最大连续子段和就可以了。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define inf int(1e9)
#define maxn 205000
#define mm 30031
#define ll long long
using namespace std;
int n,m;
ll k,d;
struct data{int l,r;ll ls,rs,ss,sum;
}t[maxn*3];

int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
void build(int i,int l,int r){
    t[i].l=l; t[i].r=r;
    if (l==r) return;
    int mid=(l+r)/2;
    build(i*2,l,mid); build(i*2+1,mid+1,r);
}
void add(int i,int pos,ll x){
    int l=t[i].l,r=t[i].r,mid=(l+r)/2;
    if (l==r){t[i].ls+=x; t[i].rs+=x; t[i].sum+=x; t[i].ss+=x;return;}
    if (pos<=mid) add(i*2,pos,x); else add(i*2+1,pos,x);
    t[i].ls=max(t[i*2].ls,t[i*2].sum+t[i*2+1].ls);
    t[i].rs=max(t[i*2+1].rs,t[i*2+1].sum+t[i*2].rs);
    t[i].sum=t[i*2].sum+t[i*2+1].sum;
    t[i].ss=max(t[i*2].ss,t[i*2+1].ss);
    t[i].ss=max(t[i].ss,t[i*2].rs+t[i*2+1].ls);
}
int main(){
    n=read(); m=read(); scanf("%lld%lld",&k,&d);
    build(1,1,n);
    rep(i,1,n) add(1,i,-k);
    rep(i,1,m){
        int r; ll x;
        scanf("%d%lld",&r,&x);
        add(1,r,x);
        if (t[1].ss<=d*k) puts("TAK");
        else puts("NIE");
    }
    
    return 0;
}

 

posted on 2015-12-15 20:16  ctlchild  阅读(177)  评论(0编辑  收藏  举报

导航