LGOJ3168-[CQOI2015] 任务查询系统(主席树+差分)

本文探讨了如何使用主席树解决超级计算机任务管理系统中的查询问题,通过构建主席树并运用差分思想,有效地实现了对任务优先级的快速查询,降低了空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题面

Description

最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先级之和。上述所有参数均为整数,时间的范围在1n之间(包含1n)。

Input

输入文件第一行包含两个空格分开的正整数mn,分别表示任务总数和时间范围。接下来m行,每行包含三个空格分开的正整数SiEiPi(Si<=Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数XiAiBiCi,描述一次查询。查询的参数Ki需要由公式 Ki=1+(AiPre+Bi)modCi计算得到。其中Pre表示上一次查询的结果,对于第一次查询,Pre=1

Output

输出共n行,每行一个整数,表示查询结果。

Solution

好题,让人深入而透彻的理解主席树。

0pts做法

拿到题,最初的想法是什么?显然是暴力加入任务,维护时间轴,而每个任务都可以代表着一段区间,自然而然地想到各种维护区间的数据结构,例如分块线段树。稍稍看一看题面就可以知道,这个其实不太可能对一段时间维护,因为每一段内的优先级们太混乱了,那么就只可能对一个时间点进行维护,因而一个任务需要EiSi棵线段树才能够维护,因而你会MLE,一分也没有。

100pts做法

上面那个算法虽然是爆零算法,但是他给我们指了一条路:用一些线段树去搞定每个任务。那么如何有效的减少空间消耗呢?注意到,一个任务是一段区间,那么这些任务们可能会有很多重叠的地方,那么我们能不能吧这些重叠的保留下来,而只新建几个节点呢?都想到这里了,那么解法就很清晰了:主席树。
但是,还有一个问题,一个任务对于这棵主席树而言是一个区间修改,似乎主席树不能这么干,怎么办?注意到主席树建树利用了前缀和的思想,那么这个区间修改也可以用同样的思想,这样才具有可移植性与可维护性。要用前缀和去实现区间修改,显然使用差分啊,所以本题就分析完了,得到如下算法:
对于每个任务,维护两棵权值线段树(想一想,为什么?),分别是Ei,Si+1这两个时间点,在Ei+1,在Si+11
然后按照时间先后顺序,将这些权值线段树merge成一棵主席树,然后就可以十分轻松的进行query了。
Talk is Cheap, Show You the Code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100005
int read(){
	 int sum=0,neg=1;
	 char c=getchar();
	 while(c>'9'||c<'0'&&c!='-') c=getchar();
	 if(c=='-') neg=-1,c=getchar();
	 while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar();
	 return sum*neg;
}
int m,n,a[N],rt[N*100],tot,lson[N*100],rson[N*100],cnt[N*100],sum[N*100];
struct Event{
	int s,e,p;
}eve[N];
inline void pushup(int now){
	 sum[now]=sum[lson[now]]+sum[rson[now]];
	 cnt[now]=cnt[lson[now]]+cnt[rson[now]];//计算优先级出现的次数 
}
void build(int &now,int l,int r,int pos,int delta){
	 if(!now) now=++tot;
	 if(l==r){
		  cnt[now]+=delta;
		  sum[now]=cnt[now]*a[l];
		  return;
	}
	 int mid=(l+r)>>1;
	 if(pos<=mid) build(lson[now],l,mid,pos,delta);
	 else build(rson[now],mid+1,r,pos,delta);
	 pushup(now);
}
int merge(int x,int y){//merge返回新的节点的编号
	if(!x||!y) return x+y;
	int now=++tot;
	sum[now]=sum[x]+sum[y];
	cnt[now]=cnt[x]+cnt[y];
	lson[now]=merge(lson[x],lson[y]);
	rson[now]=merge(rson[x],rson[y]);
	return now;
}
int query(int now,int l,int r,int k){
	 if(l==r) return a[l]*min(k,cnt[now]);//若k比现在的优先级数量还多的话,只能算数量次
	 int mid=(l+r)>>1;
	 if(cnt[lson[now]]>=k) return query(lson[now],l,mid,k);//在左儿子中查询
	 else return sum[lson[now]]+query(rson[now],mid+1,r,k-cnt[lson[now]])//在右儿子查询是,要注意加上左儿子对和的贡献,不能只算右儿子
}
signed main(){
	 m=read(); n=read();
	 //cout<<m<<" "<<n<<endl; 
	 for(int i=1;i<=m;i++){
		  eve[i].s=read();
		  eve[i].e=read();
		  eve[i].p=read();
		  a[i]=eve[i].p;
	}
	 sort(a+1,a+m+1);
	 ++n;
	 int num=unique(a+1,a+m+1)-a-1;
	 //cout<<num<<endl;
	 for(int i=1;i<=m;i++){
		  eve[i].p=lower_bound(a+1,a+num+1,eve[i].p)-a;
		  build(rt[eve[i].s],1,num,eve[i].p,1);
		  build(rt[eve[i].e+1],1,num,eve[i].p,-1);
	}
	 for(int i=1;i<=n;i++) rt[i]=merge(rt[i-1],rt[i]);
	 int pre=1;
	 for(int i=1;i<n;i++){
		  int x,a,b,c,k;
		  x=read(),a=read(),b=read(),c=read();
		  k=1+(a*pre+b)%c;
		  pre=query(rt[x],1,num,k);
		  printf("%d\n",pre);
	}
	 return 0;
}

格式难看勿喷,优快云吞缩进!!!

CH341A编程器是一款广泛应用的通用编程设备,尤其在电子工程和嵌入式系统开发领域中,它被用来烧录各种类型的微控制器、存储器和其他IC芯片。这款编程器的最新版本为1.3,它的一个显著特点是增加了对25Q256等32M芯片的支持。 25Q256是一种串行EEPROM(电可擦可编程只读存储器)芯片,通常用于存储程序代码、配置数据或其他非易失性信息。32M在这里指的是存储容量,即该芯片可以存储32兆位(Mbit)的数据,换算成字节数就是4MB。这种大容量的存储器在许多嵌入式系统中都有应用,例如汽车电子、工业控制、消费电子设备等。 CH341A编程器的1.3版更新,意味着它可以与更多的芯片型号兼容,特别是针对32M容量的芯片进行了优化,提高了编程效率和稳定性。26系列芯片通常指的是Microchip公司的25系列SPI(串行外围接口)EEPROM产品线,这些芯片广泛应用于各种需要小体积、低功耗和非易失性存储的应用场景。 全功能版的CH341A编程器不仅支持25Q256,还支持其他大容量芯片,这意味着它具有广泛的兼容性,能够满足不同项目的需求。这包括但不限于微控制器、EPROM、EEPROM、闪存、逻辑门电路等多种类型芯片的编程。 使用CH341A编程器进行编程操作时,首先需要将设备通过USB连接到计算机,然后安装相应的驱动程序和编程软件。在本例中,压缩包中的"CH341A_1.30"很可能是编程软件的安装程序。安装后,用户可以通过软件界面选择需要编程的芯片类型,加载待烧录的固件或数据,然后执行编程操作。编程过程中需要注意的是,确保正确设置芯片的电压、时钟频率等参数,以防止损坏芯片。 CH341A编程器1.3版是面向电子爱好者和专业工程师的一款实用工具,其强大的兼容性和易用性使其在众多编程器中脱颖而出。对于需要处理25Q256等32M芯片的项目,或者26系列芯片的编程工作,CH341A编程器是理想的选择。通过持续的软件更新和升级,它保持了与现代电子技术同步,确保用户能方便地对各种芯片进行编程和调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值