题目链接
http://codeforces.com/contest/1217/problem/E
题意
定义一个不平衡的multiset为集合中有某两个元素的十进制表示在某一位均有不为0。
现在给出一个数组,每次单点修改一个值,区间查询这个区间所有的数能组成的元素和最小的不平衡的multiset。
1
≤
n
≤
2
∗
1
0
5
1 \leq n \leq 2*10^5
1≤n≤2∗105
1
≤
m
≤
2
∗
1
0
5
1 \leq m \leq 2*10^5
1≤m≤2∗105
做法
很显然最终的不平衡multiset只可能有两个数,因为只要有两个数在某一位上都有值,这个multiset就是不平衡的,而且要求和最小,所以最终一定只有两个数字,那么我们只需要把每一位拆分开,建立十棵线段树,每一个线段树存储这一位有值的所有数,如果这一位没有值,那么该位置存储inf。线段树上的每个节点存储当前区间内最小的两个元素。单点修改的时候如果数字某一位为0,则把对应位的线段树上这个位置改为inf,否则改为当前要修改的数字。区间查询只需要对于十棵线段树分别查询,返回区间内最小的两个值,如果次小值为inf则说明当前区间不存在两个数在这一位上都非0,则不统计进答案,最后对每组的和取min即可。
例如样例
4 5
300 10001 20 20
2 1 3
1 1 310
2 1 3
2 3 3
2 3 4
首先构造五棵线段树。
数组分别为
第一棵: inf 10001 inf inf
第二棵: inf inf 20 20
第三棵: 300 inf inf inf
第四棵: inf inf inf inf
第五棵: inf 10001 inf inf
第一次对于每棵树区间[1,3]查询的结果分别为:(10001,inf),(20,inf),(300,inf),(inf,inf),(10001,inf),故答案为-1
之后单点更新,对于每棵树分别更新,更新之后的数组为:
第一棵: inf 10001 inf inf
第二棵: 310 inf 20 20
第三棵: 300 inf inf inf
第四棵: inf inf inf inf
第五棵: inf 10001 inf inf
第二次对于每棵树区间[1,3]查询的结果分别为:(10001,inf),(20,310),(300,inf),(inf,inf),(10001,inf),故答案为330
第三次对于每棵树区间[3,3]查询的结果分别为:(inf,inf),(20,inf),(inf,inf),(inf,inf),(inf,inf),故答案为-1
第四次对于每棵树区间[3,4]查询的结果分别为:(inf,inf),(20,20),(inf,inf),(inf,inf),(inf,inf),故答案为40
由于时间只有2s,拆位之后复杂度*10,有点卡时间,所以加了读入挂。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;
#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>
const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
ll pw[20];
namespace fastIO
{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
bool IOerror=0;
inline char nc()
{
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend)
{
p1=buf;
pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1)
{
IOerror=1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline void read(int &x)
{
bool sign=0;
char ch=nc();
x=0;
for (; blank(ch); ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
struct T
{
int l,r,mid;
int mn,mn2;
}tree[11][maxn<<2];
int a[maxn];
int tt[5];
void up(int flag,int rt)
{
int cnt=0;
tt[++cnt] = tree[flag][rt<<1].mn;
tt[++cnt] = tree[flag][rt<<1].mn2;
tt[++cnt] = tree[flag][rt<<1|1].mn;
tt[++cnt] = tree[flag][rt<<1|1].mn2;
sort(tt+1,tt+1+cnt);
tree[flag][rt].mn=tt[1];
tree[flag][rt].mn2=tt[2];
return ;
}
void build(int flag,int rt,int l,int r)
{
tree[flag][rt].l=l;
tree[flag][rt].r=r;
if(l==r)
{
int tt=a[l]/pw[flag];
if(tt%10==0)
{
tree[flag][rt].mn = INF;
tree[flag][rt].mn2 = INF;
}
else
{
tree[flag][rt].mn = a[l];
tree[flag][rt].mn2 = INF;
}
return ;
}
int mid=tree[flag][rt].mid=l+r>>1;
build(flag,rt<<1,l,mid);
build(flag,rt<<1|1,mid+1,r);
up(flag,rt);
return ;
}
void update(int flag,int rt,int pos,int val)
{
if(tree[flag][rt].l==tree[flag][rt].r)
{
tree[flag][rt].mn = val;
tree[flag][rt].mn2 = INF;
return ;
}
if(pos<=tree[flag][rt].mid) update(flag,rt<<1,pos,val);
else update(flag,rt<<1|1,pos,val);
up(flag,rt);
}
pii query(int flag,int rt,int l,int r)
{
if(tree[flag][rt].l>r&&tree[flag][rt].r<l) return pii(INF,INF);
if(tree[flag][rt].l>=l&&tree[flag][rt].r<=r)
{
return pii(tree[flag][rt].mn,tree[flag][rt].mn2);
}
pii ans=pii(INF,INF);
if(tree[flag][rt].mid>=l)
{
pii tp = query(flag,rt<<1,l,r);
ans = tp;
}
if(tree[flag][rt].mid<r)
{
pii tp = query(flag,rt<<1|1,l,r);
int cnt=0;
tt[++cnt] = tp.Fi;
tt[++cnt] = tp.Se;
tt[++cnt] = ans.Fi;
tt[++cnt] = ans.Se;
sort(tt+1,tt+1+cnt);
ans.Fi=tt[1];
ans.Se=tt[2];
}
return ans;
}
int main()
{
int n,m;
read(n);
read(m);
for(int i=1;i<=n;i++) read(a[i]);
pw[1]=1;
for(int i=2;i<=10;i++) pw[i]=pw[i-1]*10;
for(int i=1;i<=10;i++) build(i,1,1,n);
while(m--)
{
int op,x,y;
read(op);
read(x);
read(y);
if(op==1)
{
for(int i=1;i<=10;i++)
{
int tt=y/pw[i];
if(tt%10!=0) update(i,1,x,y);
else update(i,1,x,INF);
}
}
else
{
long long ans=LL_INF;
for(int i=1;i<=10;i++)
{
pii tt = query(i,1,x,y);
if(tt.Fi==INF||tt.Se==INF) continue;
else ans=min(ans,(long long )tt.Fi+tt.Se);
}
if(ans==LL_INF) printf("-1\n");
else printf("%lld\n",ans);
}
}
return 0;
}