首页 > 其他分享 >[雅礼集训 2017 Day1]市场 题解

[雅礼集训 2017 Day1]市场 题解

时间:2024-09-29 21:24:39浏览次数:7  
标签:tag1 rs int 题解 tree mid Day1 雅礼 ls

题目链接

题目分析

听说是很典的一道题,很明显难点在于除法下取整的操作。

类似花神那一道题,但是由于有区间加,所以无法进行暴力修改。

很明显暴力复杂度爆炸,考虑下取整带来的性质:

  • 对于一对相邻的数,很明显有 \(\lfloor \frac{x-1}{k}\rfloor \le \lfloor \frac{x}{k}\rfloor -1\)。
  • 我们将上面的柿子稍微做一点变形,可以得到:$x-1-\lfloor \frac{x-1}{k}\rfloor \le x-\lfloor \frac{x}{k}\rfloor $。

可见对于一个函数 \(f(x,k)=x-\lfloor \frac{x}{k}\rfloor\),是单调递增的,所以当一个区间的最大值和最小值的函数值相等时,相当于区间同时减掉同一个数(其实就是这个函数的定义),上线段树维护即可。

可以用势能分析,时间复杂度大约为 \(O(n\log n)\)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}

const int maxn=1e5+20;
int n,a[maxn],q;
struct node{
	ll sum,tag1,mn,mx;
}tree[maxn<<2];
struct segment_tree{
	inline int ls(int x){
		return x<<1;
	}
	inline int rs(int x){
		return x<<1|1;
	}
	inline void push_up(int p){
		tree[p].sum=tree[ls(p)].sum+tree[rs(p)].sum;
		tree[p].mn=min(tree[ls(p)].mn,tree[rs(p)].mn);
		tree[p].mx=max(tree[ls(p)].mx,tree[rs(p)].mx);
	}
	inline void push_down(int p,int l,int r){
		int mid=l+r>>1;
		tree[ls(p)].mn+=tree[p].tag1,tree[rs(p)].mn+=tree[p].tag1;
		tree[ls(p)].mx+=tree[p].tag1,tree[rs(p)].mx+=tree[p].tag1;
		tree[ls(p)].sum+=tree[p].tag1*(mid-l+1),tree[rs(p)].sum+=tree[p].tag1*(r-mid);
		tree[ls(p)].tag1+=tree[p].tag1,tree[rs(p)].tag1+=tree[p].tag1;
		tree[p].tag1=0;
	}
	void build(int p,int l,int r){
		tree[p].tag1=0;
		if(l==r){
			tree[p].sum=tree[p].mn=tree[p].mx=a[l];
			return;
		}
		int mid=l+r>>1;
		build(ls(p),l,mid);
		build(rs(p),mid+1,r);
		push_up(p);
	}
	void update1(int p,int l,int r,ll x,ll y,ll k){
		if(x<=l&&r<=y){
			tree[p].mn+=k,tree[p].mx+=k,tree[p].sum+=1ll*k*(r-l+1),tree[p].tag1+=k;
			return;
		}
		push_down(p,l,r);
		int mid=l+r>>1;
		if(x<=mid) update1(ls(p),l,mid,x,y,k);
		if(y>mid) update1(rs(p),mid+1,r,x,y,k);
		push_up(p);
	}
	void update2(int p,int l,int r,int x,int y,int k){
		if(x<=l&&r<=y&&(ll)floor(1.0*tree[p].mx/k)-tree[p].mx==(ll)floor(1.0*tree[p].mn/k)-tree[p].mn){
			tree[p].tag1+=(ll)floor(1.0*tree[p].mn/k)-tree[p].mn;
			tree[p].sum=tree[p].sum+((ll)floor(1.0*tree[p].mn/k)-tree[p].mn)*(r-l+1),tree[p].mn=(ll)floor(tree[p].mn*1.0/k),tree[p].mx=(ll)floor(tree[p].mx*1.0/k);
			return;
		}
		push_down(p,l,r);
		int mid=l+r>>1;
		if(x<=mid) update2(ls(p),l,mid,x,y,k);
		if(y>mid) update2(rs(p),mid+1,r,x,y,k);
		push_up(p);
	}
	ll query1(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return tree[p].mn;
		push_down(p,l,r);
		int mid=l+r>>1;
		if(y<=mid) return query1(ls(p),l,mid,x,y);
		if(x>mid) return query1(rs(p),mid+1,r,x,y);
		return min(query1(ls(p),l,mid,x,y),query1(rs(p),mid+1,r,x,y)); 
	}
	ll query2(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return tree[p].sum;
		push_down(p,l,r);
		int mid=l+r>>1;
		if(y<=mid) return query2(ls(p),l,mid,x,y);
		if(x>mid) return query2(rs(p),mid+1,r,x,y);
		return query2(ls(p),l,mid,x,y)+query2(rs(p),mid+1,r,x,y); 
	}
}S;
signed main(){
	n=read(),q=read();
	for(int i=0;i<n;i++) a[i+1]=read();
	S.build(1,1,n);
	int op,l,r,x;
	while(q--){
		op=read(),l=read(),r=read();
		l++,r++;
		if(op==1) x=read(),S.update1(1,1,n,l,r,x);
		else if(op==2) x=read(),S.update2(1,1,n,l,r,x);
		else if(op==3) printf("%lld\n",S.query1(1,1,n,l,r));
		else printf("%lld\n",S.query2(1,1,n,l,r));
	}
	return 0;
}
/*
*/

标签:tag1,rs,int,题解,tree,mid,Day1,雅礼,ls
From: https://www.cnblogs.com/dayz-break/p/18432317

相关文章

  • i++和++i的区别,面试题解析
    i++和++i都是自增操作符,用于将变量的值增加1。i++是后增操作符,它首先返回变量的值,然后再将变量的值增加1。例如,如果i的初始值为1,执行i++后,i的值变为2。++i是前增操作符,它首先将变量的值增加1,然后再返回变量的值。例如,如果i的初始值为1,执行++i后,i的值变为2。区别在于返回值的......
  • CSP-J历年真题(部分)解析与题解
    目录序言:[CSP-J2020]直播获奖前言:题目描述输入格式输出格式输入输出样例说明/提示样例1解释数据规模与约定提示65分思路及代码前言:思路:代码:85分代码及思路:前言:插入排序:思路:代码: AC思路及代码:前言:思路:   代码: [CSP-J2022]乘方前言:题目描......
  • C语言 | Leetcode C语言题解之第445题两数相加II
    题目:题解:structListNode*addTwoNumbers(structListNode*l1,structListNode*l2){intstack1[100];intstack2[100];inttop1=0;inttop2=0;intcarry=0;intsum=0;structListNode*temp=NULL;structListNode*he......
  • C语言 | Leetcode C语言题解之第443题压缩字符串
    题目:题解:voidswap(char*a,char*b){chart=*a;*a=*b,*b=t;}voidreverse(char*a,char*b){while(a<b){swap(a++,--b);}}intcompress(char*chars,intcharsSize){intwrite=0,left=0;for(intr......
  • C++ | Leetcode C++题解之第445题两数相加II
    题目:题解:classSolution{public:ListNode*addTwoNumbers(ListNode*l1,ListNode*l2){stack<int>s1,s2;while(l1){s1.push(l1->val);l1=l1->next;}while(l2){......
  • C++ | Leetcode C++题解之第443题压缩字符串
    题目:题解:classSolution{public:intcompress(vector<char>&chars){intn=chars.size();intwrite=0,left=0;for(intread=0;read<n;read++){if(read==n-1||chars[read]!=chars[read......
  • [USACO22DEC] Palindromes P 题解
    T3[USACO22DEC]PalindromesP郝题。首先考虑给定一个串\(S\)怎么求出要换多少次。易得,不可能交换两个本来就相同的字符。不妨观察\(\textttG\)的回文关系,一对\(\textttG\)回文当且仅当第一个\(\textttG\)前面的\(\textttH\)数量等于第二个\(\textttG\)后面的......
  • 【问题解决】win10日志错误:创建 TLS 客户端凭据时发生致命错误。 内部错误状态为 1001
    背景最近win10死机了一次,查看事件管理器发现有大量的报错:“创建TLS客户端凭据时发生致命错误。内部错误状态为10013”,如图:解决win键搜索internet选项确定。原因参考错误:“创建TLS客户端凭据时发生致命错误。内部错误状态为10013”的说法是win10对TLSv3.0兼容性......
  • CF1268E Happy Cactus 题解
    Description给定一张仙人掌图,第\(i\)条边连接\(u,v\),边权为\(i\)定义路径为"HappyPath"当且仅当其满足沿途边权递增。定义点对\((u,v)\)Happy当且仅当存在一条HappyPath以\(u\)为起点,\(v\)为终点。对于\(u=1,2...n\),求满足\((u,v)\)Happy的\(v\)的数量......
  • CF2019D. Speedbreaker 题解
    介绍一种另解,以下称“征服”为“拓展”。对于这些需要拓展,且拓展的时间有上界的题,我们通常都会有一个trick。那就是对于一个点\(x\),用它可以拓展到的点\(y\)的时间上界把\(x\)的时间上界继续缩小。用到这种trick的题有P9755[CSP-S2023]种树、[ABC304Ex]ConstrainedTop......