2015湖南省队集训DAY4——hoodle

弹珠 (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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值