專項測試 資料結構2
阿新 • • 發佈:2021-12-20
5a2m5Yab6aKY Q0Y1NzFE U1BPSiBDT1Q2
\[val_v^2+val_{fa_x}^2-2* val_v* val_{fa_x}+sum=w
\]\[2* val_v* val_{fa_x}+(w-val^2_{fa_x})=val^2_v+sum
\]
T1 5a2m5Yab6aKY
還不會
T2 Q0Y1NzFE
一種線上做法
兩個集合分別啟發式合併
每個1集合記錄操作權值的字首和和操作時間,2集合記錄操作時間
每個下標只會在O(log)個集合裡存在過,按照時間順序記下這些集合
詢問下標 i 時,按時間掃 i 在過的2集合,倒序找到第一個集合k,滿足k最後一次操作時 i 在k中,記下這次操作的時間 t
然後掃 1 集合,加上每個集合在 t 之後的對 i 的貢獻
時間複雜度\(O(m \log^2n)\),因為掃1集合算貢獻時每個集合要二分操作,找出並減去 i 加進這個集合之前的操作的字首和
當然在 i 加入這個集合時記一下當前字首和,就可以不用二分了
時間複雜度\(O(m\log n)\),空間複雜度\(O(n\log n)\)
T3 U1BPSiBDT1Q2
f[i] 表示 i 的子樹 鏈剖分完的最小權值和
暴力 :記 v 的父親為 u,當 v -> u 時,dfs 子樹u,到x時維護u->x這條鏈的權值,以及鏈上的點的不在鏈上的兒子的 f 的和sum,每次取min
這個複雜度是size的和,也就是祖先的數量,可惜資料不是隨的
正解 :還是這個暴力,考慮用一個式子表示一下
val[i] 表示 i 到根的點權和,sum還是那個 f 和
\[f_x=\min((val_v-val_{fa_x})^2+sum) \]v在x的子樹內,這個貢獻記為 w,拆開,交換一下
是斜率優化的形式,\((val_v,val^2_v+sum)\)是(x,y),要使截距\(b=w-val^2_{fa_x}\)最小
斜率\(2* val_{fa_x}\)有正負,維護下凸包
set維護每個子樹的凸包,子樹合併時啟發式合併,動態在最大的凸包上加點
時間複雜度\(O(n \log^2n)\)
程式碼
T2
#include<bits/stdc++.h> using namespace std; #define int long long const int N=1e5+11; struct opt_{int t,val;}; int n,m,t; int p[2][N]; int f[2][20][N],tim[2][20][N],top[2][N]; vector<int> vct[2][N]; vector<opt_> opt[2][N]; inline int max_(int x,int y){return x>y?x:y;} inline int read() { int s=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar(); return s; } inline char readc() { char ch=getchar(); while(ch>'Z'||ch<'A') ch=getchar(); return ch; } void join(int x,int y,bool jd) { x=f[jd][top[jd][x]][x]; y=f[jd][top[jd][y]][y]; if(x==y) return; if(vct[jd][p[jd][x]].size()<vct[jd][p[jd][y]].size()) swap(x,y); int px=p[jd][x],py=p[jd][y]; for(int v,i=0;i<vct[jd][py].size();++i) { v=vct[jd][py][i]; vct[jd][px].push_back(v); f[jd][++top[jd][v]][v]=x; tim[jd][top[jd][v]][v]=t; } vct[jd][py].clear(); return; } void add(int x,bool jd) { x=f[jd][top[jd][x]][x]; opt[jd][x].push_back((opt_){t,(int)vct[jd][p[jd][x]].size()}); if((!jd)&&opt[0][x].size()!=1) opt[0][x][opt[0][x].size()-1].val+=opt[0][x][opt[0][x].size()-2].val; return; } int two(int x,int tm) { if(opt[0][x].size()==0) return 0; int l=0,r=opt[0][x].size()-1; int mid,ans=0; if(tm<=opt[0][x][0].t) return opt[0][x][r].val; if(opt[0][x][r].t<tm) return 0; while(l<=r) { mid=(l+r)>>1; if(opt[0][x][mid].t<tm) l=mid+1,ans=mid; else r=mid-1; } return opt[0][x][opt[0][x].size()-1].val-opt[0][x][ans].val; } int get_ans(int x) { int ans=0; int tt=0; for(int v,i=top[1][x];i;--i) { v=f[1][i][x]; if(opt[1][v].size()==0) continue; if(opt[1][v][opt[1][v].size()-1].t>tim[1][i][x]) {tt=opt[1][v][opt[1][v].size()-1].t;break;} } for(int v,i=top[0][x];i;--i) { ans+=two(f[0][i][x],max_(tt,tim[0][i][x])); if(tim[0][i][x]<tt) break; } return ans; } signed main() { n=read(),m=read(); for(int i=1;i<=n;++i) { vct[1][i].push_back(i),vct[0][i].push_back(i); p[0][i]=p[1][i]=i; f[0][++top[0][i]][i]=i; f[1][++top[1][i]][i]=i; } for(int ch,x,y,i=1;i<=m;++i) { t=i; ch=readc(); x=read(); if(ch=='U') join(x,read(),0); else if(ch=='M') join(x,read(),1); else if(ch=='A') add(x,0); else if(ch=='Z') add(x,1); else printf("%lld\n",get_ans(x)); } return 0; }
T3
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define pll pair<int,int>
#define mkp make_pair
#define il inline
const int inf=0x7fffffffffffffff;
const int N=1e6+11;
int n;
int w[N],fa[N];
int f[N],del[N];
set<pll> st[N];
set<pll>::iterator L,M,R,ans;
vector<int> vct[N];
il int pd(int x){return x*x;}
il int max_(int x,int y){return x>y?x:y;}
il int min_(int x,int y){return x>y?y:x;}
il double get_xl(pll a,pll b){return 1.0*(a.se-b.se)/(a.fi-b.fi);}
il bool cmp(pll a,pll b,pll c){return get_xl(a,b)<get_xl(b,c);}
il int read()
{
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*w;
}
void insert(int i,pll p)
{
p.se-=del[i];
M=st[i].lower_bound(p);
if(M!=st[i].end()&&M->fi==p.fi) st[i].erase(M),M=st[i].lower_bound(p);
if(M!=st[i].begin()&&(--M)->fi==p.fi) return;
while(st[i].size())
{
M=st[i].lower_bound(p);
if(M==st[i].begin()) break;
--M;
if(M==st[i].begin()) break;
--(L=M);
if(!cmp(*L,*M,p)) st[i].erase(M);
else break;
}
while(st[i].size())
{
M=st[i].lower_bound(p);
if(M==st[i].end()) break;
++(R=M);
if(R==st[i].end()) break;
if(!cmp(p,*M,*R)) st[i].erase(M);
else break;
}
R=st[i].lower_bound(p);
if(R==st[i].end()||R==st[i].begin()) {st[i].insert(p);return;}
--(L=R);
if(!cmp(*L,p,*R)) return;
st[i].insert(p);
return;
}
int get_ans(int x)
{
if(st[x].size()==0) return inf;
int l=(*st[x].begin()).fi,r=(*st[x].rbegin()).fi,mid;
double xl=2*w[fa[x]];
ans=st[x].begin();
while(l<=r)
{
mid=(l+r)>>1;
M=st[x].lower_bound({mid,-inf});
if(M==st[x].begin()) {l=mid+1;continue;}
--(L=M);
if(get_xl(*L,*M)<xl) ans=M,l=mid+1;
else r=mid-1;
}
int sum=ans->se-2*ans->fi*w[fa[x]];
if(ans!=st[x].begin()) --ans,sum=min_(sum,ans->se-2*ans->fi*w[fa[x]]);
++ans,++ans;
if(ans!=st[x].end()) sum=min_(sum,ans->se-2*ans->fi*w[fa[x]]);
return sum+del[x]+pd(w[fa[x]]);
}
void dfs(int x)
{
w[x]+=w[fa[x]];
int sum=0,son=0;
for(int v : vct[x])
{
dfs(v);
sum+=f[v];
if(st[son].size()<st[v].size()) son=v;
}
swap(st[son],st[x]);
del[x]=del[son]+sum-f[son];
for(int v : vct[x])
if(v^son)
{
del[v]+=sum-f[v];
for(pll o : st[v]) o.se+=del[v],insert(x,o);
}
f[x]=min_(get_ans(x),pd(w[x]-w[fa[x]])+sum);
insert(x,mkp(w[x],sum+pd(w[x])));
return;
}
signed main()
{
n=read();
for(int i=1;i<=n;++i) w[i]=read();
for(int x,i=2;i<=n;++i) vct[fa[i]=read()].push_back(i);
dfs(1);
cout<<f[1]<<endl;
return 0;
}