题目链接 https://codeforc.es/problemset/problem/1217/E
题目大意:
给你一个序列
有两种操作:
1 i x,修改第i个数为x;
2 l, r 查询[l,r]区间内 不平衡子序列中元素和最小的那一个序列。
一个序列不平衡的条件是,这个序列中所有数字加起来的和中有一个十进制位的数是序列中没有一个数出现的。
如
第一个序列是平衡的因为10321这些数在序列中都有对应的出现,而第二个序列中和的十位3就没有出现,所有该序列就不平衡。
解题思路:
我们可以发现,如果两个数的某一位都不为0,那么这两个数组成的序列就不平衡了,并且我们可以证明,如果这两个数不平衡的话,我们是不能通过插入第三个数使得这两个数平衡的,所以所有不平衡子序列都可以找到一个子序列的子序列的大小为2,这个大小为2的序列是不平衡的。所有我们只要找到区间内两个数,这两个数存在着某一位都不为0,并且这两个数的和最小就行。
采用线段树维护即可。我们维护的是该区间内,个位,十位,百位,千位······该不为0的数中最小的那个数。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<unordered_map>
using namespace std;
const int maxn = 200005;
const long long inf = 0x3f3f3f3f3f3f3f3f;
struct node{
long long ans;
long long mi[9];
node(){
ans = inf;
for(int i = 0; i < 9; i++)
mi[i] = inf;
}
}tree[maxn<<2];
long long a[maxn];
void PushUp(int rt)
{
tree[rt].ans=min(tree[rt<<1].ans,tree[rt<<1|1].ans);
for(int i = 0; i < 9; i++)
{
tree[rt].ans = min(tree[rt].ans,tree[rt<<1].mi[i]+tree[rt<<1|1].mi[i]);
tree[rt].mi[i] = min(tree[rt<<1].mi[i],tree[rt<<1|1].mi[i]);
}
}
void Build(int l, int r, int rt)
{
if(l==r)
{
int cnt = 0;
long long tmp = a[l];
while(tmp)
{
if(tmp%10)
{
tree[rt].mi[cnt] = a[l];
}
tmp/=10;
cnt++;
}
return ;
}
int mid = (l+r)/2;
Build(l,mid,rt<<1);
Build(mid+1,r,rt<<1|1);
PushUp(rt);
}
void Update(int pos, long long val, int l, int r, int rt)
{
if(l==r)
{
int cnt = 0;
long long tmp = val;
while(tmp)
{
if(tmp%10)
{
tree[rt].mi[cnt] = val;
}
else
tree[rt].mi[cnt] = inf;
tmp/=10;
cnt++;
}
for(;cnt<9;cnt++)
tree[rt].mi[cnt] = inf;
return ;
}
int mid = (l+r)>>1;
if(pos<=mid) Update(pos,val,l,mid,rt<<1);
else Update(pos,val,mid+1,r,rt<<1|1);
PushUp(rt);
}
node Query(int L, int R, int l, int r, int rt)
{
if(L<=l&&R>=r)
{
return tree[rt];
}
node no[3];
int c = 0;
int mid = (l+r)>>1;
if(L<=mid) no[c++] = Query(L,R,l,mid,rt<<1);
if(R>mid) no[c++] = Query(L,R,mid+1,r,rt<<1|1);
// cout <<"&& "<< l<<" "<<r<<" "<<c<<endl;
if(c==1)
return no[0];
else
{
no[2].ans = min(no[0].ans,no[1].ans);
// cout << no[2].ans<<" "<<no[0].ans<<" "<<no[1].ans<<endl;
for(int i = 0; i < 9; i++)
{
no[2].ans = min(no[2].ans,no[0].mi[i]+no[1].mi[i]);
// cout << "++ "<<i<<" "<<no[2].ans<<" "<<no[0].mi[i]<<" "<<no[1].mi[i]<<endl;
no[2].mi[i] = min(no[0].mi[i],no[1].mi[i]);
}
return no[2];
}
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
Build(1,n,1);
// cout << tree[1].ans<<" "<<tree[2].ans<<" "<<tree[3].ans<<endl;
int op, l, r, ans;
while(m--)
{
scanf("%d%d%d", &op, &l, &r);
if(op==1)
{
Update(l,r,1,n,1);
}
else
{
node ans = Query(l,r,1,n,1);
if(ans.ans==inf)
printf("-1\n");
else
printf("%lld\n", ans.ans);
}
}
return 0;
}