GDOI2016模擬8.10查稅

題目
A 鎮剛剛成立,你被任命爲稅務局長,你的職責是保證鎮上所有公司有足夠多的會計。A 鎮主街上有N 個商業辦公室,從左到右依次編號爲1 到N,一開始所有辦公室都是空的,沒有任何公司進駐,後面陸陸續續有公司進進出出。在某一個時間段,你會巡視一段連續編號的辦公室,要求計算巡視的公司中賬戶餘額最多的是多少。

一個公司的進駐用以下四個整數來描述:

T:表示進駐是哪一天,從A 鎮成立那天算起,A 鎮成立那天算第一天;

K:進駐的辦公室的編號;

Z:該公司每天的贏利,如果虧損的話則爲負值;

S:搬進來那天公司賬戶的餘額。

如果在新公司搬進來之前第K 個辦公室已經有公司進駐,那麼這個公司會先搬出去,然後再把新公司搬進來,新搬進來的公司會在搬進來的第二天開始營業(贏利或虧損)。

你作爲稅務局長,會經常來巡視,用以下三個整數來描述:

T:巡視那天的編號;

A 和B:巡視第A 到第B 個編號範圍的辦公室。

由於巡視的時間是一天中很晚的時刻,所以所有公司已經完成當天的營業並且財務已經把當天的盈利更新到公司賬戶中。

你的任務就是對於每次巡視,找到賬戶餘額最多的公司。

這題和cf上的91E差不多,考前2天做的,但沒打出來,所以這題沒多想了。

這題可以用分塊做,對於一個快內,維護一個單調隊列,維護塊內直線方程的凸包,修改時,暴力重構,我們將快內的直線按斜率遞增加入隊列中,可以證明,當斜率遞增的3條直線a,b,c,若a與c的交點在b上面,則b不會成爲最優解,將其刪去,由於暴力排序插入回超時,可以用鏈表維護,加入時只要移動到斜率恰好比它小的地方再刪除即可。

由於詢問是時間遞增的,那麼當凸包裏A比B劣的時候,A不可能在後面比B優,刪除即可。

就這樣就可以在mn 的複雜度內解決這題

貼代碼(雖然數據有點水,我用快排+插入排序水過了,但希望大家打正解)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define MAXN 1000000000000
#define N 300001
#define M 400
using namespace std;
int n,m,s,sum;
long long d[M][M][2],e[N][2];
int g[M],a[N+N][5],b[N],t[N],l[M],r[M],q[N][5];
int did(int x){
    return (x%s>0)+x/s;
}
void ins(int x,int i){
    a[++sum][0]=q[i][3];
    a[sum][1]=q[i][4];
    a[sum][2]=q[i][1];
    a[sum][3]=q[i][2];
    a[sum][4]=g[x];
    g[x]=sum;
}
void ins1(int x,int i){
    a[++sum][0]=a[i][0];
    a[sum][1]=a[i][1];
    a[sum][2]=a[i][2];
    a[sum][3]=a[i][3];
    a[sum][4]=g[x];
    g[x]=sum;
}
void init(){
    static int x;
    scanf("%d %d",&n,&m);
    s=sqrt(n)+1;
    for (int i=1;i<=m;i++){
        scanf("%d %d %d %d",&q[i][0],&q[i][1],&q[i][2],&q[i][3]);
        if (q[i][0]==1){
            scanf("%d",&q[i][4]);
            ins(did(q[i][2]),i);
        }
    }
}
bool cmp(int x,int y){
    return a[x][0]<a[y][0];
}
void pre(){
    static int x;
    for (int i=1;i<=s;i++){
        x=0;
        for (int j=g[i];j;j=a[j][4])
            b[++x]=j;
        sort(b+1,b+x+1,cmp);
        g[i]=0;
        for (int j=x;j;j--)
            ins1(i,b[j]);
    }
}
bool jian(long long a1,long long b1,long long a2,long long b2,long long a3,long long b3){
    return (long long)(b1-b2)*(a1-a3)<=(long long)(b3-b1)*(a2-a1);
}
void ins(int x,int a,long long b){
    r[x]++;
    while (r[x]>=3&&jian(a,b,d[x][r[x]-2][0],d[x][r[x]-2][1],d[x][r[x]-1][0],d[x][r[x]-1][1]))r[x]--;
    d[x][r[x]][0]=a,d[x][r[x]][1]=b;
}
void rebuild(int x){
    static int y;
    l[x]=1,r[x]=0;
    for (int i=g[x];i;i=a[i][4])
        if (t[a[i][3]]==a[i][2])
            ins(x,a[i][0],a[i][1]-(long long)a[i][0]*a[i][2]);
}
long long find(long long t,int x){
    if (!l[x])return -MAXN;
    while (l[x]<r[x]&&d[x][l[x]][0]*t+d[x][l[x]][1]<=d[x][l[x]+1][0]*t+d[x][l[x]+1][1])l[x]++;
    return d[x][l[x]][0]*t+d[x][l[x]][1];
}
void work(){
    static int x,y;
    static long long ans;
    for (int i=1;i<=m;i++)
        if (q[i][0]==1)e[q[i][2]][0]=q[i][3],e[q[i][2]][1]=q[i][4]-(long long)q[i][3]*q[i][1],t[q[i][2]]=q[i][1],rebuild(did(q[i][2]));
        else{
            if (q[i][2]>q[i][3])swap(q[i][2],q[i][3]);
            x=did(q[i][2]),y=did(q[i][3]);
            ans=-MAXN;
            for (int j=x+1;j<y;j++)
                ans=max(ans,find(q[i][1],j));
            if (x==y){
                for (int j=q[i][2];j<=q[i][3];j++)
                    if (t[j])
                        ans=max(ans,(long long)e[j][0]*q[i][1]+e[j][1]);
            }else{
                for (int j=min(x*s,n);j>=q[i][2];j--)
                    if (t[j])
                        ans=max(ans,(long long)e[j][0]*q[i][1]+e[j][1]);
                for (int j=(y-1)*s+1;j<=q[i][3];j++)
                    if (t[j])
                        ans=max(ans,(long long)e[j][0]*q[i][1]+e[j][1]);
            }
            if (ans==-MAXN)printf("nema\n");
            else
            printf("%lld\n",ans);
        }
}
int main(){
    init();
    pre();
    work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章