1. 程式人生 > 其它 >luogu P3591 [POI2015]ODW

luogu P3591 [POI2015]ODW

題面傳送門
發現自己寫了個屑的\(O(n\sqrt nlogn)\)做法。
首先這種走\(k\)步的東西想到根號分治。
設閾值\(B\),若\(C>B\)的話那麼就暴力跳,時間複雜度\(O(\sqrt nlogn)\)
\(C\leq B\)的話那麼對於每個\(C\)一起處理,每次做一遍倍增就好了。這個單次倍增時間複雜度\(O(nlogn)\)
然後\(B=\sqrt n\)就可以取到理論最優\(O(n\sqrt nlogn)\),如果長剖可以\(O(n\sqrt {nlogn})\)
交上去一看T成\(50\)分。考慮第一個常數其實很小,再加上出題人如果要卡你肯定是一堆小C,所以閾值放小一點,我放到\(40\)

輕鬆跑過。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 50000
#define mod 998244353
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int lcas,n,m,k,x,y,z,B[N+5],C[N+5],Ans[N+5],Val[N+5],fa[N+5][20],lg[N+5],d[N+5],F[N+5][20],W[N+5][20];
struct Qu{int x,y,id;}now;vector<Qu>Q[N+5];
struct yyy{int to,z;};
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;
I void dfs(int x,int last){
	fa[x][0]=last;d[x]=d[last]+1;int i;yyy tmp;for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(dfs(tmp.to,x),0);
}
I void swap(int &x,int &y){x^=y^=x^=y;}
I int lca(int x,int y){
	d[x]<d[y]&&(swap(x,y),0);while(d[x]^d[y]) x=fa[x][lg[d[x]-d[y]]];if(x==y) return x;for(int i=lg[d[x]];~i;i--)fa[x][i]&&fa[y][i]&&fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]);return fa[x][0];
}
I int kth(int x,int k){while(k) x=fa[x][lg[k&-k]],k-=k&-k;return x;}
I void Make(int x,int last,int k){
	F[x][0]=kth(x,k);W[x][0]=Val[x];int i;yyy tmp;for(i=1;F[x][i-1];i++) F[x][i]=F[F[x][i-1]][i-1],W[x][i]=W[x][i-1]+W[F[x][i-1]][i-1];for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(Make(tmp.to,x,k),0);
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j,h;scanf("%d",&n);for(i=2;i<=n;i++) lg[i]=lg[i/2]+1;k=40;for(i=1;i<=n;i++)scanf("%d",&Val[i]);for(i=1;i<n;i++)scanf("%d%d",&x,&y),s.add(x,y),s.add(y,x);dfs(1,0);
	for(i=1;i<=n;i++) scanf("%d",&B[i]);for(i=1;i<n;i++)scanf("%d",&C[i]);for(i=1;i<n;i++) C[i]<=k&&(Q[C[i]].push_back((Qu){B[i],B[i+1],i}),0);for(i=1;i<n;i++){if(C[i]<=k) continue;
		x=B[i];y=B[i+1];
		Ans[i]=Val[y]+Val[x];lcas=lca(x,y);z=d[x]+d[y]-2*d[lcas];if(z<C[i]) continue;if(z%C[i]>d[y]-d[lcas]) y=kth(x,d[x]-d[lcas]-(z%C[i]-(d[y]-d[lcas])));else y=kth(y,z%C[i]);z%C[i]&&(Ans[i]+=Val[y]);
		lcas=lca(x,y);while(d[x]-C[i]>=d[lcas]) x=kth(x,C[i]),Ans[i]+=Val[x];while(d[y]-C[i]>=d[lcas]) y=kth(y,C[i]),Ans[i]+=Val[y];(x==y)&&(Ans[i]-=Val[x]);
	}
	for(i=1;i<=k;i++){
		if(!Q[i].size())continue;Me(F,0);Me(W,0);Make(1,0,i);for(j=0;j<Q[i].size();j++){
			now=Q[i][j];x=now.x;y=now.y;lcas=lca(x,y);z=d[x]+d[y]-2*d[lcas];if(z<i) {Ans[now.id]=Val[x]+Val[y];continue;}z%i&&(Ans[now.id]+=Val[y]);if(z%i>d[y]-d[lcas]) y=kth(x,d[x]-d[lcas]-(z%i-(d[y]-d[lcas])));else y=kth(y,z%i);
			lcas=lca(x,y);for(h=lg[d[x]];~h;h--) F[x][h]&&(d[F[x][h]]>=d[lcas])&&(Ans[now.id]+=W[x][h],x=F[x][h]);for(h=lg[d[y]];~h;h--) F[y][h]&&(d[F[y][h]]>=d[lcas])&&(Ans[now.id]+=W[y][h],y=F[y][h]);/*printf("%d %d %d\n",x,y,Ans[now.id]);*/Ans[now.id]+=Val[x]+Val[y];(x==y)&&(Ans[now.id]-=Val[lcas]);
		} 
	}for(i=1;i<n;i++) printf("%d\n",Ans[i]);
}