dtoj#3699. 胖(joke)

題目描述:

Cedyks 是九條可憐的好朋友(可能這場比賽公開之後就不是了),也是這題的主人公。node

Cedyks 是一個富有的男孩子。他住在著名的The Place(宮殿)中。c++

Cedyks 是一個努力的男孩子。他天天都作着不同的題來鍛鍊他的The Salt(靈魂)。git

這天,他打算在他的宮殿外圍修築一道城牆,城牆上有 $ n $ 座瞭望塔。你能夠把城牆看作一條線段,瞭望塔是線段上的 $ n $ 個點,其中 $ 1 $ 和 $ n $ 分別爲城牆的兩個端點。其中第 $ i $ 座瞭望塔和第 $ i+1 $ 座瞭望塔的距離爲 $ w_i $ ,他們之間的道路是雙向的。算法

城牆很快就修建好了,如今Cedyks 開始計劃修築他的宮殿到城牆的道路。由於這題的題目名稱,Cedyks 打算用他的宮殿到每個瞭望塔的最短道路之和來衡量一個修建計劃。數組

如今Cedyks 手上有 $ m $ 個設計方案,第 $ k $ 個設計方案會在宮殿和瞭望塔之間修建 $ T_k $ 條雙向道路,第 $ i $ 條道路鏈接着瞭望塔 $ a_i $ ,長度爲 $ l_i $ 。ide

計算到每個瞭望塔的最短路之和是一個繁重的工程,原本Cedyks 想用廣爲流傳的SPFA算法來求解,可是由於他的butter(緩衝區)實在是過小了,他只能轉而用原始的貝爾福特曼算法來計算,算法的流程大概以下:spa

$ 1. $ 定義宮殿是 $ 0 $ 號點,第 $ i $ 個瞭望塔是 $ i $ 號點,雙向邊 $ u_i,v_i,l_i $ 爲一條鏈接 $ u_i $ 和 $ v_i $ 的雙向道路。令 $ d $ 爲距離數組,最開始 $ d_0=0,d_i=10^{18}(i \in [1,n]) $ 。設計

$ 2. $ 令輔助數組 $ c=d $ 。依次對於每一條邊 $ u_i,v_i,w_i $ 進行增廣, $ c_{u_i}=min(c\_{u_i},d_{v_i}+w_i),c_{v_i}=min(c_{v_i},d_{u_i}+w_i) $ 。code

$ 3. ​$ 令 $ t ​$ 爲 $ c ​$ 和 $ d ​$ 中不同位置個數,即令 $ S=\{i|c_i \neq d_i\} ​$ ,則 $ t=|S| ​$ 。若 $ t=0 ​$ ,說明 $ d ​$ 就是最終的最短路,算法結束。不然令 $ d=c ​$ ,回到第二步。blog

由於須要計算的設計方案實在是太多了,因此Cedyks 僱傭了一些人來幫他進行計算。爲了不這些人用捏造出來的數據偷懶,他定義一個設計方案的校驗值爲在這個方案上運行貝爾福特曼算法每一次進入第三步 $ t $ 的和。他會讓好幾個僱傭來的人計算一樣的設計方案,並比對每個人給出的校驗值。

你是Cedyks 僱傭來的苦力之一,聰明的你發如今這個情形下計算最短路的長度的和是一件很是簡單的事情。可是寄人籬下不得不低頭,你不得再也不計算出每個方案的校驗值來交差。

思路:

對於一個瞭望塔,他所能覆蓋的必定是一段連續的區間,因此咱們能夠經過二分找到它的左右端點。

對於一個端點 $x$ 它能被瞭望塔 $p$ 覆蓋的條件是:

令 $p,x$ 的距離爲 $d$

在 $[x-d,x+d]$ 的範圍內沒有其餘瞭望塔到 $x$ 的距離小於 $p$ 到 $x$ 的距離。(等於的狀況有特別處理,後文說明)。

那麼意味着咱們要求一段連續區間內的瞭望塔到某個單點的距離的最小值,若是咱們令 $dis[x]$ 表示端點 $x$ 到 $1$ 的距離,那麼瞭望塔到單點的距離等於 $|dis[p]-dis[x]|+l$ 。爲了去掉絕對值,咱們對於瞭望塔在右的狀況記錄 $dis[p]+l$ ,並用 $st$ 表維護區間最小值。對於瞭望塔在左的狀況記錄 $dis[p]-l$ 維護區間最大值。

接下來對於距離相等的狀況,首先若是是瞭望塔右側的部分咱們能夠優先選擇距離最貼近瞭望塔的,也就是座標小的,在左側的類比。

若是對於在瞭望塔兩邊且到瞭望塔的座標相等的,咱們能夠規定選擇小的那一邊,這樣就能保證只被選擇一次。

如下代碼:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5;
LL dis[N],v1[N],v2[N];
int n,m,k,Lg[N],st1[N][21],st2[N][21],p[N];
struct node{
    int x,l;
}t[N];
il int read(){
   int x,f=1;char ch;
   _(!)ch=='-'?f=-1:f;x=ch^48;
   _()x=(x<<1)+(x<<3)+(ch^48);
   return f*x;
}
bool cmp(node t1,node t2){
    return t1.x<t2.x;
}
il int Min(int t1,int t2){
    if(v1[t1]==v1[t2])return t1<t2?t1:t2;
    return (v1[t1]<v1[t2])?t1:t2;
}
il int Max(int t1,int t2){
    if(v2[t1]==v2[t2])return t1<t2?t2:t1;
    return (v2[t1]>v2[t2])?t1:t2;
}
il int getmn(int l,int r){
    int k=Lg[r-l+1];
    return Min(st1[l][k],st1[r-(1<<k)+1][k]);
}
il int getmx(int l,int r){
    int k=Lg[r-l+1];
    return Max(st2[l][k],st2[r-(1<<k)+1][k]);
}
il bool pd1(int x,int y){
    int l=(x<<1)-p[y],r=y,mid;
    l=lower_bound(p+1,p+1+k,l)-p;
    mid=upper_bound(p+1,p+1+k,x)-p-1;
    LL len=abs(dis[p[y]]-dis[x])+t[y].l;
    if(l<=mid){
        int t1=getmx(l,mid);
        if(dis[x]-v2[t1]<len)return 0;
        
        if(dis[x]-v2[t1]==len&&y!=t1){
            if(abs(p[t1]-x)<abs(p[y]-x))return 0;
            if(abs(p[t1]-x)==abs(p[y]-x)&&t1<y)return 0;
        }
    }
    
    if(mid<r){
        int t2=getmn(mid+1,r);
        if(v1[t2]-dis[x]<len)return 0;
        if(v1[t2]-dis[x]==len&&y!=t2){
            if(abs(p[t2]-x)<abs(p[y]-x))return 0;
            if(abs(p[t2]-x)==abs(p[y]-x)&&t2<y)return 0;
        }
    }
    return 1;
}
il bool pd2(int x,int y){
    
    int l=y,r=(x<<1)-p[y],mid;
    r=upper_bound(p+1,p+1+k,r)-p-1;
    mid=upper_bound(p+1,p+1+k,x)-p-1;
    LL len=abs(dis[p[y]]-dis[x])+t[y].l;
    
    if(l<=mid){
        int t1=getmx(l,mid);
        if(dis[x]-v2[t1]<len)return 0;
        if(dis[x]-v2[t1]==len&&y!=t1){
            if(abs(p[t1]-x)<abs(p[y]-x))return 0;
            if(abs(p[t1]-x)==abs(p[y]-x)&&t1<y)return 0;
        }
    }
    if(mid<r){
        int t2=getmn(mid+1,r);
        if(v1[t2]-dis[x]<len)return 0;
        if(v1[t2]-dis[x]==len&&y!=t2){
            if(abs(p[t2]-x)<abs(p[y]-x))return 0;
            if(abs(p[t2]-x)==abs(p[y]-x)&&t2<y)return 0;
        }
    }
    return 1;
}
int main()
{
    n=read();m=read();
    for(int i=2;i<=n;i++)dis[i]=dis[i-1]+read(),Lg[i]=Lg[i>>1]+1;
    for(int i=1;i<=m;i++){
        k=read();
        for(int i=1;i<=k;i++)t[i].x=read(),t[i].l=read();
        sort(t+1,t+1+k,cmp);
        for(int i=1;i<=k;i++)p[i]=t[i].x;
        for(int i=1;i<=k;i++)
            v1[i]=t[i].l+dis[t[i].x],v2[i]=dis[t[i].x]-t[i].l;
        for(int i=1;i<=k;i++)st1[i][0]=i,st2[i][0]=i;
        for(int j=1;j<=Lg[k];j++)for(int i=1;i+(1<<j)-1<=k;i++)
            st1[i][j]=Min(st1[i][j-1],st1[i+(1<<(j-1))][j-1]),
            st2[i][j]=Max(st2[i][j-1],st2[i+(1<<(j-1))][j-1]);
        LL ans=0;
        for(int i=1;i<=k;i++){
            int l=1,r=t[i].x,res=r;
            while(l<=r){
                int mid=(l+r)>>1;
                if(pd1(mid,i))res=mid,r=mid-1;
                else l=mid+1;
            }
            int kk=res;
            l=t[i].x,r=n,res=l;
            while(l<=r){
                int mid=(l+r)>>1;
                if(pd2(mid,i))res=mid,l=mid+1;
                else r=mid-1;
            }
            ans+=res-kk+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索