1. 程式人生 > 其它 >專項測試 資料結構2

專項測試 資料結構2

5a2m5Yab6aKY Q0Y1NzFE U1BPSiBDT1Q2

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^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 \]

是斜率優化的形式,\((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;
}