「NOIP赛前冲刺」KDOI-03T1 还原数据
Solution
首先可以看出,之前的 操作会被之后的 操作覆盖,考虑倒着解决问题。
那么问题转化成:对于最终的数列 ,通过一系列的区间减和区间取 ,得到最先的数列 ,构造每次取 的 。
注意到如何时刻数列的数永远比上一个时刻大。
通过观察,设当前的数列为 ,可以得出一个合法的方案 ,证明如下:
记 ,若 ,则反过来操作(即顺着操作)该操作是 ,无法得到 ,故 。
然后证明 一定是解,记 表示在此次操作之后的最小值(即顺着操作时的上一步的最小值),注意到反过来操作(即顺着操作)时 ,当 时不用关心 的取值,所以一直都取 一定可以得到最终答案。
: 并不是代表一定无解,这代表 ,那么代表之前的一次操作的 要较大才可以,但这可能会导致两种情况:
- 另一次的 要较小,并且为了这个要求,还有一个 要较大,一个 要较小······
- 在这个操作的区间前面没有 操作了,无法得出 。
综上所述,可以用一颗线段树来维护。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
using db=double;
using ll=long long;
using vi=vector<int>;
using pii=pair<int,int>;
using pq=priority_queue<int,vector<int>,greater<int> >;
using ull=unsigned long long;
#define ft first
#define sd second
#define gc getchar
#define pb push_back
#define emp emplace_back
#define mp make_pair
#define ls p*2
#define rs p*2+1
#define sz(a) (int)a.size()
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define int long long
const int N=1e6+7;
const int mod=998244353;
const int INF=(1ll<<60);
const int inf=INT_MAX;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
void write(int x) {
char ch[20];
int len = 0;
if (x < 0)putchar('-'), x = -x;
while (x) {
ch[len++] = (x % 10) ^ 48;
x /= 10;
}
if(len==0)printf("0");
while (len--)putchar(ch[len]);
putchar(' ');
}
int mn[N],lazy[N],a[N],op[N],tl[N],tr[N],tx[N],ans[N];
void addlazy(int p,int x)
{
mn[p]+=x;
lazy[p]+=x;
}
void pushdown(int p)
{
addlazy(ls,lazy[p]);
addlazy(rs,lazy[p]);
lazy[p]=0;
}
void build(int p,int l,int r)
{
if(l==r)
{
mn[p]=a[l];
return;
}
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
mn[p]=min(mn[ls],mn[rs]);
}
void add(int p,int l,int r,int L,int R,int x)
{
if(L<=l&&r<=R)
{
addlazy(p,x);
return;
}
pushdown(p);
int mid=(l+r)/2;
if(L<=mid)add(ls,l,mid,L,R,x);
if(R>mid)add(rs,mid+1,r,L,R,x);
mn[p]=min(mn[ls],mn[rs]);
}
int query(int p,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return mn[p];
int mid=(l+r)/2,mn=INF;
pushdown(p);
if(L<=mid)mn=min(mn,query(ls,l,mid,L,R));
if(R>mid)mn=min(mn,query(rs,mid+1,r,L,R));
return mn;
}
void solve()
{
int n,q,tot=0;
read(n),read(q);
memset(lazy,0,sizeof lazy);
FOR(i,1,n)read(a[i]);
FOR(i,1,q)
{
read(op[i]),read(tl[i]),read(tr[i]);
if(op[i]==1)read(tx[i]);
}
FOR(i,1,n)read(a[i]);
build(1,1,n);
ROF(i,q,1)
{
if(op[i]==1)add(1,1,n,tl[i],tr[i],-tx[i]);
else
{
int Mn=query(1,1,n,tl[i],tr[i]);
ans[++tot]=Mn;//注意到不用关心mn'的值,这里甚至不用更新
}
}
ROF(i,tot,1)write(ans[i]);
puts("");
}
signed main()
{
int T;
read(T);
while(T--)solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现