把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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]);
} 
posted @ 2021-08-04 22:05  275307894a  阅读(51)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end