• [POI2009]Lyz


    Description
    初始时滑冰俱乐部有1到n号的溜冰鞋各k双。已知x号脚的人可以穿x到x+d的溜冰鞋。 有m次操作,每次包含两个数ri,xi代表来了xi个ri号脚的人。xi为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。

    Input
    n m k d ( 1≤n≤200,000 , 1≤m≤500,000 , 1≤k≤10^9 , 0≤d≤n ) ri xi ( 1≤i≤m, 1≤ri≤n-d , |xi|≤10^9 )

    Output
    对于每个操作,输出一行,TAK表示够 NIE表示不够。

    Sample Input
    4 4 2 1
    1 3
    2 3
    3 3
    2 -1

    Sample Output
    TAK
    TAK
    NIE
    TAK


    这题好难,完全不懂原理……以下转载CRZbulabula的博客

    Hall定理

    把俱乐部的人看做点集X,溜冰鞋看做点集Y

    显然这是一个二部图

    根据Hall定理,如果存在饱和点集X的匹配,那么(forall S subseteq X),(|N(S)| geqslant |S|)

    N(S)是Y中与X相邻的点的集合

    对于此题,Hall定理最容易取到反例的状况一定是连续一段区间

    因为此时能用来容纳X匹配的对应的Y总不多于不连续的区间

    那么就是说,(forall sumlimits_{i=l}^r A_i leqslant (r - l + 1 + d) imes k)

    两边同时-k,得(sumlimits_{i=1}^n (A_i-k) leqslant d imes k)

    于是,我们只需要维护连续序列的最大值就行了

    线段树解决

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)     print(x/10);
    	putchar(x%10+'0');
    }
    const int N=2e5;
    int n,m,k,d;
    struct Segment{
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	struct node{
    		ll le,ri,sum,now;
    		node(){le=ri=now=sum=0;}
    		node(ll a,ll b,ll c,ll d){le=a,ri=b,sum=c,now=d;}
    		void insert(ll x){le=ri=now=sum=x;}
    	}tree[(N<<2)+10];
    	friend node operator +(const node &x,const int v){return node(x.le+v,x.ri+v,x.sum+v,x.now+v);}
    	friend node operator +(const node &x,const node &y){
    		node z;
    		z.now=max(max(x.now,y.now),x.ri+y.le);
    		z.le=max(x.le,x.sum+y.le);
    		z.ri=max(y.ri,x.ri+y.sum);
    		z.sum=x.sum+y.sum;
    		return z;
    	}
    	void build(int p,int l,int r){
    		if (l==r){
    			tree[p].insert(-k);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(ls,l,mid),build(rs,mid+1,r);
    		tree[p]=tree[ls]+tree[rs];
    	}
    	void change(int p,int l,int r,int x,ll v){
    		if (l==r){
    			tree[p]=tree[p]+v;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if (x<=mid)	change(ls,l,mid,x,v);
    		else	change(rs,mid+1,r,x,v);
    		tree[p]=tree[ls]+tree[rs];
    	}
    }Tree;
    int main(){
    	n=read(),m=read(),k=read(),d=read();
    	Tree.build(1,1,n); 
    	for (int i=1;i<=m;i++){
    		int x=read(),v=read();
    		Tree.change(1,1,n,x,v);
    		printf(Tree.tree[1].now>1ll*k*d?"NIE
    ":"TAK
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Treat wchar_t as built-in type不一致导致的链接错误
    C++ const关键字总结
    安全学习资料网站(持续更新欢迎补充)
    移动端https抓包那些事--进阶篇
    移动端https抓包那些事--初级篇
    drozer工具的安装与使用:之二使用篇
    drozer工具的安装与使用:之一安装篇
    信息安全学习笔记--CSRF
    信息安全学习笔记--XSS
    // 日期操作 封装一些日期常用操作
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9101994.html
Copyright © 2020-2023  润新知