[luogu5654]基礎函數練習題

答案即區間$[l,r]$的笛卡爾樹上,左右子樹有一個爲空的點到根路徑和(定義此爲的該點答案)的max,c++

對求區間笛卡爾樹複雜度爲$o(n)$,沒法經過,所以在全局笛卡爾樹中考慮此問題數組

設$k$爲$l$和$r$的lca,那麼$i$的答案就是$i$到$k$路徑中在$[l,r]$中的部分的和ide

對於$i$所在子樹分類,即將$[l,r]$分爲$[l,k)$和$(k,r]$兩部分(分別求max),如下以左半部分爲例:spa

考慮$i$到$k$的鏈,因爲$i$在$k$左子樹中,所以這條鏈也時刻在$k$左子樹中,即其必定在$k$也就是$r$的左邊,所以只須要考慮這個位置大於等於$l$it

進一步的,再求$l$和$i$的lca(記爲$j$),因爲是lca且$l\le i$,所以$l$必定在$j$的左子樹中,$i$在$j$的右子樹中,所以$i$到$j$的這一部分必定都在$l$的右邊,換言之能夠枚舉lca,直接對右子樹內全部點深度取maxclass

還要考慮$j$到$k$的部分,即求這一部分中在$l$右邊的數之和,這件事是與$l$無關而僅和$j$自己有關,凡是這條鏈上其兒子是其右兒子的都不能被計算date

(由於這就說明了$k$在其右子樹,$l$又在$k$子樹內,即$l$在其的右邊,反之就說明$l$在左邊)搜索

根據上面的性質,具體過程以下——遍歷

預處理出如下三個數組:$s_{1}[k]$表示$k$到根路徑中全部點的和,$s_{2}[k]$表示其中全部兒子是左兒子的點之和(特別的,$k$都計算入內),$mx[k]$表示$k$子樹中知足左右子樹有一個爲空的點的$s_{1}[k]$的最大值im

考慮詢問$[l,k)$,暴力枚舉$j$,則對於給定的$j$,其對答案的貢獻爲$mx[rs[j]]-s_{1}[j]+s_{2}[j]-s_{2}[k]+w[k]$(注意$j$必定在$l$的右邊,不然不多是$l$和$i$的lca),貢獻是取max

離線,將詢問掛在$l$上,而後遍歷笛卡爾樹,對於點$k$,將$mx[rs[k]]-s_{1}[k]+s_{2}[k]$記在以$k$的深度爲下標的線段樹上,而後搜索左子樹,當搜索右子樹時撤銷此記錄

對於詢問,求出$k$(指詢問的頂點)的深度+1到$l$的深度這段區間在線段樹上的最大值便可(因爲$l$的右子樹也是能夠的,所以先修改再詢問)

(右半部分相似,即只考慮其兒子是右兒子的點)

注意要開long long,時間複雜度爲$o(n\log_{2}n)$,能夠經過

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define ll long long
 5 #define L (k<<1)
 6 #define R (L+1)
 7 #define mid (l+r>>1)
 8 vector<pair<int,int> >vl[N],vr[N];
 9 int n,q,x,y,a[N],w[N],st[N],ls[N],rs[N],s[N],f[N][21];
10 ll s1[N],s2[N],s3[N],mx[N],ans[N],tr[N<<2]; 
11 int lca(int x,int y){
12     if (s[x]<s[y])swap(x,y);
13     for(int i=20;i>=0;i--)
14         if (s[f[x][i]]>=s[y])x=f[x][i];
15     if (x==y)return x;
16     for(int i=20;i>=0;i--)
17         if (f[x][i]!=f[y][i]){
18             x=f[x][i];
19             y=f[y][i];
20         }
21     return f[x][0];
22 }
23 void dfs(int k,int fa){
24     if (!k)return;
25     s[k]=s[fa]+1;
26     s1[k]=s1[fa]+w[k];
27     s2[k]+=s2[fa]+w[k];
28     s3[k]+=s3[fa]+w[k];
29     f[k][0]=fa;
30     for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
31     if (ls[k])s3[ls[k]]=-w[k];
32     dfs(ls[k],k);
33     if (rs[k])s2[rs[k]]=-w[k];
34     dfs(rs[k],k);
35     mx[k]=max(mx[ls[k]],mx[rs[k]]);
36     if ((!ls[k])||(!rs[k]))mx[k]=max(mx[k],s1[k]);
37 }
38 void update(int k,int l,int r,int x,ll y){
39     if (l==r){
40         tr[k]=y;
41         return;
42     }
43     if (x<=mid)update(L,l,mid,x,y);
44     else update(R,mid+1,r,x,y);
45     tr[k]=max(tr[L],tr[R]);
46 }
47 ll query(int k,int l,int r,int x,int y){
48     if ((l>y)||(x>r))return -1e15;
49     if ((x<=l)&&(r<=y))return tr[k];
50     return max(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
51 }
52 void calc_l(int k){
53     if (!k)return;
54     if (!rs[k])update(1,1,n,s[k],s2[k]);
55     else update(1,1,n,s[k],mx[rs[k]]-s1[k]+s2[k]);
56     for(int i=0;i<vl[k].size();i++){
57         x=vl[k][i].first,y=vl[k][i].second;
58         ans[y]=max(ans[y],query(1,1,n,s[x]+1,s[k])-s2[x]+w[x]);
59     }
60     calc_l(ls[k]);
61     update(1,1,n,s[k],-1e15);
62     calc_l(rs[k]);
63 }
64 void calc_r(int k){
65     if (!k)return;
66     if (!ls[k])update(1,1,n,s[k],s3[k]);
67     else update(1,1,n,s[k],mx[ls[k]]-s1[k]+s3[k]);
68     for(int i=0;i<vr[k].size();i++){
69         x=vr[k][i].first,y=vr[k][i].second;
70         ans[y]=max(ans[y],query(1,1,n,s[x]+1,s[k])-s3[x]+w[x]);
71     }
72     calc_r(rs[k]);
73     update(1,1,n,s[k],-1e15);
74     calc_r(ls[k]);
75 }
76 int main(){
77     scanf("%d%d",&n,&q);
78     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
79     for(int i=1;i<=n;i++)scanf("%d",&w[i]);
80     for(int i=1;i<=n;i++){
81         while ((st[0])&&(a[st[st[0]]]<a[i]))ls[i]=st[st[0]--];
82         if (st[0])rs[st[st[0]]]=i;
83         st[++st[0]]=i;
84     }
85     mx[0]=-1e15;
86     dfs(st[1],0);
87     for(int i=1;i<=q;i++){
88         scanf("%d%d",&x,&y);
89         int z=lca(x,y);
90         ans[i]=max(s2[x]-s2[z],s3[y]-s3[z])+w[z];
91         if (x<z)vl[x].push_back(make_pair(z,i));
92         if (z<y)vr[y].push_back(make_pair(z,i));
93     }
94     for(int i=1;i<=n;i++)update(1,1,n,i,-1e15);
95     calc_l(st[1]);
96     calc_r(st[1]);
97     for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
98 } 
View Code
相關文章
相關標籤/搜索