多校第8场P7

本文介绍了如何使用线段树解决区间加法操作和查询区间内最小最大值的问题。通过将序列分成固定大小的块,并维护每块之间的相邻影响,实现了O(qlogn)的时间复杂度。作者分享了自己在比赛中遇到的挑战,包括对复杂数据结构的掌握和优化,并对自己的表现进行了反思。
摘要由CSDN通过智能技术生成

前言:水篇文章,感觉是道好题
题意:支持区间加,已经区间查询 m i n ( m a x ( a i . . . a i + K − 1 ) ) ( l < = i < = i + K − 1 < = r ) min(max(a_i...a_{i+K-1}))(l<=i<=i+K-1<=r) min(max(ai...ai+K1))(l<=i<=i+K1<=r)
K固定, 2 ⩽ K ⩽ n ⩽ 5 ∗ 1 0 8 , q ⩽ 2 ∗ 1 0 5 2\leqslant K \leqslant n \leqslant 5*10^8,q\leqslant 2*10^5 2Kn5108,q2105
题解:把原序列分成n/K块,每块长度为K,于是一段长K的就是横跨两块的
考虑维护相邻两段的影响
考虑区间加,对此的影响除了区间加,还有 O ( 1 ) O(1) O(1)部分的区间重构
解决重构,保证每块的线段树同构即可,于是就没了
时空的复杂度 O ( q l o g 2 n ) O(qlog_2n) O(qlog2n)
一点小bb:考场上写了双log还写挂了(写对了也会T),不会同构的菜鸡博主是屑。
打了四场HDU,RK是15,8,10,6
四场我都是半程不到就歇菜了,都是CY在猛带,感觉我给力一点,可能就会有次rk前三的(最后一场打表unsigned int不加u的博主是屑)
今天打了Luogu,A是FLS带了一手才会的,我是屑
明天就是百度之星复赛了,这状态估计进不了决赛了
后面的路我也不知道该干啥,估计自己不是那么纯粹了

#include<bits/stdc++.h>
using namespace std;

#define cout cerr
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)

#define FR first
#define SE second
typedef long long ll;
typedef pair<int,int> pii;

inline void rd(int &x){
	x=0;char ch=getchar();int f=1;
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}

int n,K,q,len;//[1,len)
#define Maxn 100010
#define V 15000010
const int inf=1e9+5;

struct Node{
	int mx,mn,tg;
	int v;
	int ls,rs;
	Node(){mx=mn=tg=v=ls=rs=0;}
	void init(){mx=mn=tg=v=ls=rs=0;}
}tree[V];
map<int,int> mp;int tot;
int rt[Maxn<<1],root,cnt=0;
void newnode(int &k){
	k=++cnt;
	tree[k].init();
}
void push_up(int k){
	int ls=tree[k].ls,rs=tree[k].rs;
	tree[k].mx=max(tree[ls].mx,tree[rs].mx);
	tree[k].mn=min(tree[ls].mn,tree[rs].mn);
}
void make_tag(int &k,int t){
	if(!k)newnode(k);
	tree[k].mx+=t;tree[k].mn+=t;tree[k].tg+=t;
}
void push_down(int k){
	make_tag(tree[k].ls,tree[k].tg);make_tag(tree[k].rs,tree[k].tg);
	tree[k].tg=0;
}
void ADD(int k,int l,int r,int L,int R,int t){
	if(l==L&&r==R){
		make_tag(k,t);
		return;
	}
	push_down(k);
	int mid=(l+r)>>1;
	if(R<=mid)ADD(tree[k].ls,l,mid,L,R,t);
	else if(mid<L)ADD(tree[k].rs,mid+1,r,L,R,t);
	else{
		ADD(tree[k].ls,l,mid,L,mid,t);
		ADD(tree[k].rs,mid+1,r,mid+1,R,t);
	}
	push_up(k);
}
void addv(int k,int l,int r,int L,int R,int t){
	if(l==L&&r==R){
		tree[k].v+=t;
		return;
	}
	push_down(k);
	int mid=(l+r)>>1;
	if(R<=mid)addv(tree[k].ls,l,mid,L,R,t);
	else if(mid<L)addv(tree[k].rs,mid+1,r,L,R,t);
	else{
		addv(tree[k].ls,l,mid,L,mid,t);
		addv(tree[k].rs,mid+1,r,mid+1,R,t);
	}
}
void Modify(int k,int l,int r,int p,int t){
	if(l==r){
		tree[k].mn=tree[k].mx=t;
		return;
	}
	push_down(k);
	int mid=(l+r)>>1;
	if(p<=mid)Modify(tree[k].ls,l,mid,p,t);
	else Modify(tree[k].rs,mid+1,r,p,t);
	push_up(k);
}
int query(int k,int l,int r,int p){
	if(l==r)return tree[k].v;
	int mid=(l+r)>>1;
	if(p<=mid)return tree[k].v+query(tree[k].ls,l,mid,p);
	else return tree[k].v+query(tree[k].rs,mid+1,r,p);
}

int qmin(int k,int l,int r,int L,int R){
	if(l==L&&r==R)return tree[k].mn;
	int mid=(l+r)>>1;
	if(R<=mid)return qmin(tree[k].ls,l,mid,L,R)+tree[k].tg;
	else if(mid<L)return qmin(tree[k].rs,mid+1,r,L,R)+tree[k].tg;
	else return min(qmin(tree[k].ls,l,mid,L,mid),qmin(tree[k].rs,mid+1,r,mid+1,R))+tree[k].tg;
}

void calc(int x,int l,int r,int t){
	l=max(l,x*K-K+1);r=min(r,x*K);
	if(l>r)return;
	l-=(x-1)*K;r-=(x-1)*K;
	if(!mp[x]){
		mp[x]=++tot;
		newnode(rt[tot]);
	}
	ADD(rt[mp[x]],1,K,l,r,t);
}

int gao(int k1,int k2,int l,int r,int L,int R,int v1,int v2){
	if(l==r)return v1+tree[k1].mx;
	int mid=(l+r)>>1;
	v1+=tree[k1].tg;v2+=tree[k2].tg;
	if(R<=mid||mid<L){
		if(R<=mid)return max(v2+tree[tree[k2].rs].mx,gao(tree[k1].ls,tree[k2].ls,l,mid,L,R,v1,v2));
		else return max(v1+tree[tree[k1].ls].mx,gao(tree[k1].rs,tree[k2].rs,mid+1,r,L,R,v1,v2));
	}
	int s1=v1+tree[tree[k1].ls].mx,s2=v2+tree[tree[k2].rs].mx;
	if(s1>s2){
		return min(s1,max(s2,gao(tree[k1].ls,tree[k2].ls,l,mid,L,mid,v1,v2)));
	}else return min(s2,max(s1,gao(tree[k1].rs,tree[k2].rs,mid+1,r,mid+1,R,v1,v2)));
}

int run(int l,int r,int p){
	l=max(l,p*K-K+1);r=min(r,p*K+K);
	l=p*K-l+1;r-=p*K;
	int v1=query(root,1,len,p+1),v2=query(root,1,len,p),res=inf;
	if(max(1,K-l)<=r)res=min(res,gao(rt[mp[p+1]],rt[mp[p]],1,K,max(1,K-l),r,v1,v2));
	if(l>=K)res=min(res,v2+tree[rt[mp[p]]].mx);
	return res;
}

void calculate(int l,int r){
	int tl=(l+K-1)/K,tr=r/K;
	int res=min(run(l,r,tl),run(l,r,tr));
	if(tl<tr-1)res=min(res,qmin(root,1,len,tl+1,tr-1));
	printf("%d\n",res);
}

void Run(int x){
	if(x<1||x>=len)return;
	Modify(root,1,len,x,run((x-1)*K+1,(x+1)*K,x));
}

void init(){
	cnt=0;tot=0;
	mp.clear();
	newnode(root);
}

int main(){
	int T;
	rd(T);
	while(T--){
		rd(n);rd(K);rd(q);
		len=n/K;len++;n=(len+1)*K;
		init();
		int opt,l,r,x;
		rep(i,1,q){
			rd(opt);rd(l);rd(r);
			if(opt==2)calculate(l,r);
			else{df 
				rd(x);
				if(tl<tr-1)ADD(root,1,len,tl+1,tr-1,x);
				calc(tl,l,r,x);if(tr+1!=tl)calc(tr+1,l,r,x);
				if(tl+1<=tr)addv(root,1,len,tl+1,tr,x);
				Run(tl);Run(tl-1);Run(tr);Run(tr+1);
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值