2017.11.7 T3 2046
样例数据
输入
3 3
1 1
2 2
3 3
2 10
1 1 6 6
2 10
输出
10
9
分析:哎,T2耗时太久,本来可以打一下这道题的20%暴力的,说一下正解:
将所有的物品价值、价格和物品修改操作的都存下来,离散化按价值(从大到小)为第一关键字、价格(从小到大)为第二关键字排序,建一棵线段树(存价格),每一层的值都是下两层中较小的一个,这样在线段树上查找时只要左边的价格还能买就往左走(因为左边的价值更高),找到能买的物品。对于修改操作,显然不能在修改之前就买到这种价格的东西,所以就把价格赋值成INF,在枚举到这个修改后才把价格赋成修改后的,再把原价格赋成INF,也就没法买原来这种价格的东西了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
const int N=100005,INF=0x3f3f3f3f;
int n,m,cnt;
int b[N<<1],tree[N<<3];
struct node
{
int k,w,p,id;
inline friend bool operator <(const node &a,const node &b)
{
if(a.w==b.w)return a.preturn a.w>b.w;
}
}a[N],t[N<<1],q[N];
void lsh()
{
for(int i=1;i<=n;++i)
t[++cnt]=a[i],t[cnt].id=i;
for(int i=1;i<=m;++i)
if(q[i].w!=-1)
t[++cnt]=q[i],t[cnt].id=i;
}
void buildtree(int num,int l,int r)
{
if(l==r)
{
tree[num]=t[l].p;
return;
}
int mid=l+r>>1;
buildtree(num<<1,l,mid);
buildtree(num<<1|1,mid+1,r);
tree[num]=min(tree[num<<1],tree[num<<1|1]);
}
void modify(int num,int l,int r,int p,int v)
{
if(l==r)//找到位置后修改价格
{
t[l].p=tree[num]=v;
return;
}
int mid=l+r>>1;
if(p<=mid)
modify(num<<1,l,mid,p,v);
else
modify(num<<1|1,mid+1,r,p,v);
tree[num]=min(tree[num<<1],tree[num<<1|1]);
}
node query(int num,int l,int r,int v)
{
if(l==r)//找到位置后返回能买的东西的所有信息(价格、价值)
return t[l];
int mid=l+r>>1;
if(tree[num<<1]<=v)//只要左边能走就走左边
return query(num<<1,l,mid,v);
else
return query(num<<1|1,mid+1,r,v);
}
int main()
{
freopen("shopping.in","r",stdin);
freopen("shopping.out","w",stdout);
n=getint(),m=getint();
for(int i=1;i<=n;++i)//物品存下来
a[i].w=getint(),a[i].p=getint();
for(int i=1;i<=m;++i)//修改询问也都存下来
{
int op=getint();
if(op==1)
q[i].k=getint(),q[i].w=getint(),q[i].p=getint();
else
q[i].k=getint(),q[i].w=-1;
}
lsh();//离散化
sort(t+1,t+cnt+1);//按我说的关键字排序
for(int i=1;i<=cnt;++i)
if(!t[i].k)//是物品就把离散化后它的位置给它
a[t[i].id].id=i;
else//是修改操作也把离散化后它的位置给它,并把要建树的价格赋成INF
q[t[i].id].id=i,t[i].p=INF;
buildtree(1,1,cnt);
for(int i=1;i<=m;++i)
{
if(q[i].w!=-1)//碰到修改操作
{
modify(1,1,cnt,a[q[i].k].id,INF);//把原来的价格赋成INF
modify(1,1,cnt,q[i].id,q[i].p);//把新价格附进去
a[q[i].k].id=q[i].id;//给物品新价值编号
}
else//碰到查询操作
{
long long ans=0;
while(q[i].k>=tree[1])//只要还能买(tree[1]是整棵树里最小的价格)就买
{
node tmp=query(1,1,cnt,q[i].k);
ans+=(long long)q[i].k/tmp.p*tmp.w;//可以买多次
q[i].k%=tmp.p;//更新钱
}
cout<'\n';//输出答案
}
}
return 0;
}
本题结。