E-card

E-card

题目描述

 

两个人各有n张牌

第一个人有n-1张平民和1张皇帝

第二个人有n-1张平民和1张奴隶

每次选择一张牌 进行对决 如果都是平民则平局

皇帝赢平民 奴隶赢皇帝 平民赢奴隶(显然只会有一局会不是平局 那局就是决胜局)

现在你是奴隶方 已知皇帝方是个沙茶 每次会在现有的手牌中随便选一张出 问你的最优决策(即在哪次出奴隶)

本来这是个沙茶问题 但是皇帝方有一天觉醒了 他不再每次随便选一张出 而是第i次以一个概率p选择出皇帝 1-p出平民

皇帝方对第i次出皇帝有估算一个收益vi(初始为0)

第i次出皇帝的概率是vi/Σv

当然皇帝方会改变他的看法(根据你的表情0 0)但是因为他是沙茶 他对他的猜想又不是很确定╮(╯_╰)╭ 所以他会在心里想一个模拟收益数组u(初始为0)

每次选择4个数L,R,a,b对于i (L<=i<=R)

u[i]更新为max(u[i], (i – L) * a + b)

在某个时刻他会确定他某次的猜想比较好 然后他会让v[i]=u[i] 这时候你会想知道你当前应该在哪出奴隶(如果多个最优解 输出最小的那个)

 

 

输入

 

第一行三个整数 n,m

代表n张牌 m次操作

接下来m行

如果第一个数是1 则后面跟4个数代表L,R,a,b

如果第一个数是2 则后面跟1个数i 代表把v[i]赋值为u[i] 并输出当前最优位置

对于30%的数据 n <= 10^5, m <= 1000

对于100%的数据n<=10^9, m<=100000, 1 <= L <= R <= n, |a,b|<=10^9

 

 

输出

 

每行一个数表示询问的结果

 

 

样例输入


1 5 10 -8 2
2 4
1 3 8 3 1
2 4
2 5
2 6
2 7
2 8

样例输出

1
4
5
6
7
8

 

 

 

怪题,浪费一下午

solution

对于 (i – L) * a + b

把它化为i*a-L*a+b 即一段一次函数(k=a,b=-L*a+b)

把区间(L,R)打上标记(k,b)

考虑如何处理已有标记的区间

假设有标记(k1,b1)

我要加入(k2,b2)

不妨设k1>k2

分类:

1.若b1>b2   保留(k1,b1)

 

2,b1<b2  这就麻烦了

k1*x+b1-k2*x-b2

t=(b2-b1)/(k1-k2)(取下整)

所以x>t 取k1,b1

x<=t k2,b2

再分类

t<l  取k1,b1

 

t>=r 取k2,,b2

 

l<t<=mid  左儿子全取k2,b2,右儿子未知

则 k保留k2,b2,递归更新右儿子

 

mid<t<r 右儿子全取k1,b1,左儿子未知

则 k保留k1,b1 递归更新左儿子

 

查询时,把i到根的路径取max

这样就可以了。

 

因为,对于一个点,可能造成贡献的答案,一定在i到根的路径上。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,m,pl,mp,tot;
long long maxv,li,ri,a1,b1;
struct no{
    long long k,b;
};
struct node{
    no x;long long ls,rs;
}tree[100005*42];
void ma(long long &k){
    if(!k)k=++tot;
}
void orz(long long k,long long L,long long R,no a){ 
    if(!tree[k].x.k)tree[k].x=a;
    else {  
        if(a.k>tree[k].x.k)swap(a,tree[k].x);
        if(a.b<=tree[k].x.b){return;}//k1>k2 b1>b2
        if(a.k==tree[k].x.k){tree[k].x.b=max(tree[k].x.b,a.b);return;}
        long long k1=a.k,k2=tree[k].x.k,b1=a.b,b2=tree[k].x.b;
        long long t=(b2-b1)/(k1-k2);
        long long mid=L+R>>1;
        if(t<L){return;}//k1 b1
        if(t>=R){tree[k].x=a;return;}//k2 b2
        if(t<=mid){//mid+1~r  k1b1
            ma(tree[k].ls);
            orz(tree[k].ls,L,mid,a);
        }
        if(t>mid){//l~mid k2b2
            swap(a,tree[k].x);
            ma(tree[k].rs);
            orz(tree[k].rs,mid+1,R,a);
        }
    }
}
void lian(long long k,long long L,long long R,no a){
    if(L>=li&&R<=ri){
        orz(k,L,R,a);
        return;
    }
    long long mid=L+R>>1;
     
    if(li<=mid){
        ma(tree[k].ls);
        lian(tree[k].ls,L,mid,a);
    }
    if(ri>mid){
        ma(tree[k].rs);
        lian(tree[k].rs,mid+1,R,a);
    }
}
long long ask(long long k,long long L,long long R){
    if(!k)return 0;
    if(L==R){
        return tree[k].x.k*pl+tree[k].x.b;
    }
    long long mid=L+R>>1;
    long long t=0;
    if(tree[k].x.k)t=max(t,tree[k].x.k*pl+tree[k].x.b); 
    if(pl<=mid)t=max(t,ask(tree[k].ls,L,mid));
    else t=max(t,ask(tree[k].rs,mid+1,R));
    return t;
}
int main()
{
    cin>>n>>m;tot=1;
    maxv=0;mp=1;
    for(long long i=1;i<=m;i++){
        long long op;
        scanf("%lld",&op);
        if(op==1){
            scanf("%lld%lld%lld%lld",&li,&ri,&a1,&b1);
            no ne;ne.k=a1,ne.b=-a1*li+b1;
            //cout<<ne.k<<' '<<ne.b<<endl;
            lian(1,1,n,ne);
        }
        else {
            scanf("%lld",&pl);
            long long t=ask(1,1,n);
            if(t>maxv)maxv=t,mp=pl;
            if(t==maxv)mp=min(mp,pl);
            printf("%lld\n",mp);
        }
    }
    return 0;
}
 

猜你喜欢

转载自blog.csdn.net/liankewei123456/article/details/81513508