• Luogu P4064 [JXOI2017]加法


    题解 传送门

    按照套路

    先把区间按左端点排序
    然后再来思考怎么使最小值最大???
    .
    .
    .
    想到了啥???

    二分答案!!!

    所以思路就很清晰了
    先二分答案
    对于每个二分出来的值去check:
    1.扫一遍点
    2.对于达不到这个值的每个点,把区间按右端点从大到小依次加上,知道该点的值满足条件
    3.同时记录所花费的区间个数
    4.如果2和3有任意一个不满足,即是不符合的

    对于覆盖了当前点的区间的右端点的大小,可以用堆维护一下 (倒是跟 这题 蛮像的)
    加区间的操作直接用树状数组就好了

    小细节: 由于我码风丑陋,数组开到4e5就TLE飞了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define in inline
    #define get getchar()
    #define db double
    in int read()
    {
    	int t=0,x=1; char ch=get;
    	while ((ch<'0' || ch>'9') && ch!='-') ch=get;
    	if (ch=='-') ch=get, x=-1;
    	while (ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    	return t*x;
    }
    const int _=4e5+5;
    struct region{
    	int x,y;
    }r[_];
    int n,m,k,add,a[_],sum[_];
    in int cmp(region a,region b)
    {
    	return a.x<b.x;
    }
    
    in int lowbit(int x){
    	return x&-x;
    }
    in void insert(int x,int y)
    {
    	for(re int i=x;i<=n;i+=lowbit(i)) sum[i]+=y;
    }
    in int query(int x)
    {
    	int ans=0;
    	for(re int i=x;i>=1;i-=lowbit(i)) ans+=sum[i];
    	return ans;
    } //树状数组基本操作
    
    in int check(int x)
    {
    	priority_queue<int>q; //存满足条件的区间的右端点
    	int j=1,tot=0;
    	memset(sum,0,sizeof(sum));
    	for (re int i=1;i<=n;i++)
    	{
    		int kkk=query(i);//当前点已经加上了的区间的值
    		while(r[j].x<=i&&j<=m)
    		{
    			q.push(r[j].y);
    			j++;
    		} //当前区间满足条件,将其右端点压入堆
    		while(!q.empty() && kkk+a[i]<x&&q.top()>=i&&tot<=k) //当前点的值太小,需要加上一些区间
    		{
    			insert(i,add);
    			insert(q.top()+1,-add); 
    			kkk=query(i); //树状数组基于差分实现的区间修改,单点查询 
    			q.pop(); //记得把此区间弹掉
    			tot++; //记录使用的区间个数
    		}
    		if(kkk+a[i]<x||tot>k)return 0;
    	}
    	return 1;
    }
    int main()
    {
    	int t=read();
    	while(t--)
    	{
    		n=read(),m=read(),k=read(),add=read();
    		for (re int i=1;i<=n;i++) a[i]=read();
    		for (re int i=1;i<=m;i++)
    			r[i].x=read(),r[i].y=read();
    		sort (r+1,r+1+m,cmp);
    		int L=add,R=2e9,res,mid;
    		while (L<=R)
    		{
    			mid=(L+R)>>1;
    			if (check(mid)) res=mid,L=mid+1;
    			else R=mid-1;
    		} //二分答案
    		cout<<res<<endl;
    	}
    }
    
    
    

    有史以来,yzhx第一次写这么多注释

    嗯,就这样了...
  • 相关阅读:
    html文件上传函数
    form上传以及下载文件回调
    WIN2008R2 64位平台IIS发布WEB项目 未在本地计算机上注册“MICROSOFT.ACE.OLEDB.12.0"错误提示
    回文数
    搜索旋转排序数组
    Kotlin注解处理(Kapt)
    关于@FeignClient的属性源码分析
    sonatype-nexus私服的搭建与settings的设置
    简话ReentrantLock的可重入锁概念
    springboot2.1与单节点redis的集成实战
  • 原文地址:https://www.cnblogs.com/yzhx/p/10656039.html
Copyright © 2020-2023  润新知