弹珠 (hoodle)
【问题描述】
D.Ash 是一个喜欢玩弹珠的小男孩,他有一盒五颜六色的弹珠,在阳光的照射下非
美丽。
同样,他喜欢聆听弹珠相碰时的清脆声音。
经过他的观察,每个弹珠有三个参数 , , ,均为正整数,
分别为弹珠的碰撞损耗,发射损耗和发射能量,
用弹珠 x 撞击弹珠 y ,发出的声音响度为 B_{x,y}=max{- * + ,0}。
Ash 会把弹珠从弹珠盒中拿出来插入到现有弹珠序列中,戒替换现有弹珠序列中已
的弹珠,
Ash 会先告诉你操作的类型, “Insert” 表示插入, “Change” 表示替换。
Ash 的每个操作有两个参数 t, 。
若操作类型为 “Insert”,表示把碰撞损耗为 的弹珠插入到当前序列第 t 个弹珠之
后,t=0 表示将该弹珠插入到当前序列的第一个。
若操作类型为 “Change”,表示把当前序列第 t 个弹珠之后的弹珠修改为碰撞损耗为
的弹珠,t=0 表示修改当前序列的第一个弹珠。
Ash 要玩这么一个游戏:
他先把第一颗弹珠放入袋中,然后从袋子中取出一颗弹珠撞击第二颗弹珠,
然后把第二颗弹珠收入袋中,然后从袋子中取出一颗弹珠撞击第三颗弹珠,
然后把第三颗弹珠收入袋中,然后从袋子中取出一颗弹珠撞击第四颗弹珠,
以此类推………
对亍第 i 颗弹珠 (i!=1),可以使用前 i-1 颗弹珠中的任何一颗来撞击它 ,并且每颗
珠可以使用多次。
Ash 告诉你,经过他的摆放,保证当前序列中 , 是单调上升的。
他希望你能告诉他,对亍第 2~n 颗弹珠中的每颗弹珠的最大撞击响度是多少。
【输入格式】
第 1 行,两个数,n,m。
第 2~m+1 行,每行一个字符串和两个数,表示操作。
第 m+2~m+1+n 行,每行两个数,分别为 和 。
【输出格式】
输出 n-1 行,每行一个数,第 i 行表示第 i+1 弹珠的最大撞击响度。
【样例输入】
5 10
Insert 0 10
Change 0 2
Insert 0 2
Change 0 10
Insert 2 4
Insert 1 8
Change 1 2
Change 0 5
Insert 1 2
Change 1 4
1 5
2 10
3 14
4 17
5 19
【样例输出】
1
6
8
2
【样例解释】
第1 次操作后,序列为{10}
第2 次操作后,序列为{2}
第3 次操作后,序列为{2,2}
第4 次操作后,序列为{10,2}
第5 次操作后,序列为{10,2,4}
第6 次操作后,序列为{10,8,2,4}
第7 次操作后,序列为{10,2,2,4}
第8 次操作后,序列为{5,2,2,4}
第9 次操作后,序列为{5,2,2,2,4}
第10 次操作后,序列为{5,4,2,2,4}
对亍第2颗弹珠,B_{1,2}=1, 最大值为 1
对亍第3颗弹珠,B_{1,3}=3,B_{2,3}=6,最大值为 6
对亍第4颗弹珠,B_{1,4}=3,B_{2,4}=6,B_{3,4}=8,最大值为8
对亍第5颗弹珠,B_{1,5}=1,B_{2,5}=2,B_{3,5}=2,B_{4,5}=1,最大值为 2
【数据范围】
对亍前 30% 的数捤, n <= 1000, m <= 3000
对亍前 50% 的数捤, n <= 10000,m <= 20000
对亍 100% 的数捤, n <= 400000,m <= 500000,0< , , <= 10^9
数捤是有梯度的。
题解+吐槽:
是在去年湖南集训时听说splay这东西的,那时年轻,啥都不懂,没想到现在这种东西已经是sb玩意了。
是在更早的时候听说斜率优化这东西的,那时年轻,啥都不懂,没想到现在连我都能写出来了。
这题是俩基础题拼起来的。
第一个任务是维护序列。
因为没有强制在线,所以可以倒序处理,用线段树/树状数组维护。
然而我傻逼只会splay。
第二个任务是求一个看上去就是斜率优化的东西。
还顺便送了个点的坐标递增的条件。
于是直接上单调栈,维护上凸壳。
然后每次询问时在上凸壳上二分查找满足条件的点。
再就是一些细节问题,稍不注意就会写挂。。。
(P.S.这题的数据生成器真是淡腾)
代码在这:
(因为是考场代码,所以会有些奇怪的注释,而且为了方便(我懒癌晚期),我把splay在暴力部分里粘了一份,然后就6k了。。。另外还有快速输出)
#include <cstdio>
const int inf=0x3f3f3f3f;
using namespace std;
typedef long long ll;
typedef double db;
int getint()
{
int f=1,g=0;
char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9')g=(g<<3)+(g<<1)+c-'0',c=getchar();
return f*g;
}
int n,m;
template<class T>
T max(const T& a,const T& b)
{
return a>b? a:b;
}
namespace brute_force{
#define lc ch[x][0]
#define rc ch[x][1]
#define key_value ch[ch[root][1]][0]
const int maxn=900005;
int pre[maxn];
int ch[maxn][2];
int val[maxn];
int size[maxn];
int root;
int tot;
int all;
int a[maxn];
int p[maxn];
int q[maxn];
int newnode(int v,int fa)
{
int x=++tot;
lc=rc=0;
pre[x]=fa;
val[x]=v;
size[x]=1;
return x;
}
void up(int x)
{
size[x]=size[lc]+size[rc]+1;
}
void rotate(int x)
{
int y=pre[x];
int f=(ch[y][0]==x);
pre[x]=pre[y];
pre[ch[x][f]]=y;
ch[y][!f]=ch[x][f];
if(pre[y])
{
ch[pre[y]][ch[pre[y]][1]==y]=x;
}
pre[y]=x;
ch[x][f]=y;
up(y);
up(x);
}
void splay(int x,int goal)
{
while(pre[x]!=goal)
{
int y=pre[x],z=pre[y];
if(pre[y]!=goal){
if((ch[z][0]==y)^(ch[y][0]==x))rotate(x);
else rotate(y);
}
rotate(x);
}
up(x);
if(goal==0)root=x;
}
int findk(int x,int k){
if(!x)return 0;
if(k<=size[lc])return findk(lc,k);
if(k>size[lc]+1)return findk(rc,k-size[lc]-1);
return x;
}
void split(int l,int r)
{
splay(findk(root,l),0);
splay(findk(root,r+2),root);
}
void insert(int p,int v)
{
split(p,p-1);
key_value=newnode(v,ch[root][1]);
up(ch[root][1]);
up(root);
}
void modify(int p,int v)
{
split(p,p);
val[key_value]=v;
}
void run(int x)
{
if(!x)return;
run(lc);
if(val[x]!=inf && val[x]!=-inf)
{
//printf("%d ",val[x]);
a[++all]=val[x];
}
run(rc);
}
void init()
{
root=newnode(-inf,0);
ch[root][1]=newnode(inf,root);
up(ch[root][1]);
up(root);
}
void test()
{
init();
int T=getint();
while(T--)
{
int opt=getint();
if(opt==1)
{
int x=getint();
int y=getint();
insert(x,y);
}
else if(opt==2)
{
int x=getint();
int y=getint();
modify(x,y);
}
run(root);
puts("");
}
}
char opt[20];
int f[maxn];
db slope(int j,int k)
{
return (db)(q[j]-q[k])/(db)(p[j]-p[k]);
}
int qu[maxn];
int l,r;
inline void print(ll x)
{
if(!x){putchar('0');return;}
if(x>=10)print(x/10);
putchar('0'+x%10);
}
void solve()
{
init();
for(int i=1;i<=m;i++)
{
scanf("%s",opt);
if(opt[0]=='C')
{
int x=getint();
int y=getint();
modify(x+1,y);
}
else
{
int x=getint();
int y=getint();
insert(x+1,y);
}
}
run(root);
l=1;
for(int i=1;i<=n;i++)
{
p[i]=getint();
q[i]=getint();
}
for(int i=2;i<=n;i++)
{
ll mx=0;
for(int j=1;j<i;j++)
{
mx=max((ll)q[j]-(ll)a[i]*(ll)p[j],mx);
}
print(mx);
putchar('\n');
}
}
}
namespace another_brute_force{
#define lc ch[x][0]
#define rc ch[x][1]
#define key_value ch[ch[root][1]][0]
const int maxn=900005;
int pre[maxn];
int ch[maxn][2];
int val[maxn];
int size[maxn];
int root;
int tot;
int all;
int a[maxn];
int p[maxn];
int q[maxn];
inline int newnode(const int& v,const int& fa)
{
int x=++tot;
lc=rc=0;
pre[x]=fa;
val[x]=v;
size[x]=1;
return x;
}
inline void up(int x)
{
size[x]=size[lc]+size[rc]+1;
}
void rotate(int x)
{
int y=pre[x];
int f=(ch[y][0]==x);
pre[x]=pre[y];
pre[ch[x][f]]=y;
ch[y][!f]=ch[x][f];
if(pre[y])
{
ch[pre[y]][ch[pre[y]][1]==y]=x;
}
pre[y]=x;
ch[x][f]=y;
up(y);
up(x);
}
void splay(int x,int goal)
{
while(pre[x]!=goal)
{
int y=pre[x],z=pre[y];
if(pre[y]!=goal){
if((ch[z][0]==y)^(ch[y][0]==x))rotate(x);
else rotate(y);
}
rotate(x);
}
up(x);
if(goal==0)root=x;
}
int findk(int x,int k){
if(!x)return 0;
if(k<=size[lc])return findk(lc,k);
if(k>size[lc]+1)return findk(rc,k-size[lc]-1);
return x;
}
void split(int l,int r)
{
splay(findk(root,l),0);
splay(findk(root,r+2),root);
}
void insert(int p,int v)
{
split(p,p-1);
key_value=newnode(v,ch[root][1]);
up(ch[root][1]);
up(root);
}
void modify(int p,int v)
{
split(p,p);
val[key_value]=v;
}
void run(int x)
{
if(!x)return;
run(lc);
if(val[x]!=inf && val[x]!=-inf)
{
//printf("%d ",val[x]);
a[++all]=val[x];
}
run(rc);
}
inline void init()
{
root=newnode(-inf,0);
ch[root][1]=newnode(inf,root);
up(ch[root][1]);
up(root);
}
void test()
{
init();
int T=getint();
while(T--)
{
int opt=getint();
if(opt==1)
{
int x=getint();
int y=getint();
insert(x,y);
}
else if(opt==2)
{
int x=getint();
int y=getint();
modify(x,y);
}
run(root);
puts("");
}
}
char opt[20];
ll f[maxn];
inline db slope(int j,int k)
{
return (db)(q[j]-q[k])/(db)(p[j]-p[k]);
}
int qu[maxn];
int l,r;
inline void print(ll x)
{
if(!x){putchar('0');return;}
if(x>=10)print(x/10);
putchar('0'+x%10);
}
void solve()
{
init();
for(int i=1;i<=m;i++)
{
scanf("%s",opt);
if(opt[0]=='C')
{
int x=getint();
int y=getint();
modify(x+1,y);
}
else
{
int x=getint();
int y=getint();
insert(x+1,y);
}
}
run(root);
l=1;
for(int i=1;i<=n;i++)
{
if(i!=1)
{
int lll=l;
int rr=r;
while(lll<rr)
{
int mid=(lll+rr)>>1;
if(slope(qu[mid+1],qu[mid])>a[i])
{
lll=mid+1;
}
else
{
rr=mid;
}
}
ll temp=-(ll)a[i]*(ll)p[qu[lll]]+(ll)q[qu[lll]];
temp=max(temp,0ll);
print(temp);
//puts("");
putchar('\n');
//printf("%lld\n",temp);
}
p[i]=getint();
q[i]=getint();
while(l<r && slope(qu[r],qu[r-1])<slope(qu[r],i))r--;
qu[++r]=i;
}
}
}
//expected score 100
int main()
{
freopen("hoodle.in","r",stdin);
freopen("hoodle.out","w",stdout);
n=getint();m=getint();
/**/
if(n<=10000)brute_force::solve();
else
/**/
another_brute_force::solve();
return 0;
}