zoukankan      html  css  js  c++  java
  • 【BZOJ4381】[POI2015] ODW(设阈值+倍增)

    点此看题面

    大致题意: 给定一棵树,每次从树上一点(x)以步长(k)走向另一点(y),若最后距离(y)不足(k)则一步到达(y),求经过的点权和。

    设阈值

    对于这种题目,我们可以根据(k)(sqrt n)的大小关系分类讨论:

    • (k>sqrt n):直接暴力走,树上倍增找到下一步到达的地方即可。
    • (klesqrt n):预处理出一个点向根节点步长为(i)时经过的点权和,差分即可求出答案。

    具体实现可能有些细节,详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50000
    #define LN 20
    #define SN 300
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define swap(x,y) (x^=y^=x^=y)
    using namespace std;
    int n,sn,a[N+5],b[N+5],c[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    		#undef D
    }F;
    class Tree
    {
    	private:
    		int d[N+5],f[N+5][LN+5],g[N+5][SN+5];
    		I int LCA(RI x,RI y)//倍增LCA
    		{
    			RI i;for(d[x]<d[y]&&swap(x,y),i=0;d[x]^d[y];++i) (d[x]^d[y])>>i&1&&(x=f[x][i]);
    			if(x==y) return x;for(i=LN;~i;--i) f[x][i]^f[y][i]&&(x=f[x][i],y=f[y][i]);return f[x][0];
    		}
    		I int Jump(RI x,CI D)//跳到x深度为D的祖先
    		{
    			RI i;for(i=0;d[x]^D;++i) (d[x]^D)>>i&1&&(x=f[x][i]);return x;
    		}
    	public:
    		I void dfs(CI x=1)//预处理
    		{
    			RI i;for(i=1;i<=LN;++i) f[x][i]=f[f[x][i-1]][i-1];
    			for(i=1;i<=sn;++i) g[x][i]=(d[x]>=i?g[Jump(x,d[x]-i)][i]:0)+a[x];//预处理
    			for(i=lnk[x];i;i=e[i].nxt) e[i].to^f[x][0]&&
    				(d[e[i].to]=d[f[e[i].to][0]=x]+1,dfs(e[i].to),0);
    		}
    		I int BF(RI x,RI y,CI s)//暴力跳
    		{
    			RI z=LCA(x,y),t=a[x];W(d[x]-s>=d[z]) t+=a[x=Jump(x,d[x]-s)];//从x向上跳
    			RI p=(d[x]+d[y]-(d[z]<<1))%s;p&&(t+=a[y],y=Jump(y,d[y]-p));//处理不完整的一步
    			W(t+=a[y],d[y]-s>=d[z]) y=Jump(y,d[y]-s);return x==y&&(t-=a[z]),t;//从y向上跳
    		}
    		I int GetAns(CI x,RI y,CI s)
    		{
    			RI z=LCA(x,y),u=Jump(x,d[z]>d[x]%s?d[x]%s+((d[z]-d[x]%s-1)/s+1)*s:d[x]%s);//求出x向上跳到的深度最小的点
    			RI t=g[x][s]-g[u][s]+a[u];//差分
    			RI p=(d[u]+s+d[y]-(d[z]<<1))%s;p&&(t+=a[y],y=Jump(y,d[y]-p));//处理不完整的一步
    			RI v=Jump(y,d[z]>d[y]%s?d[y]%s+((d[z]-d[y]%s-1)/s+1)*s:d[y]%s);//求出y向上跳到的深度最小的点
    			return t+=g[y][s]-g[v][s]+a[v],u==v&&(t-=a[z]),t;
    		}
    }T;
    int main()
    {
    	RI i,x,y;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);
    	for(i=1;i^n;++i) F.read(x),F.read(y),add(x,y),add(y,x);sn=sqrt(n),T.dfs();
    	for(i=1;i<=n;++i) F.read(b[i]);for(i=1;i^n;++i) F.read(c[i]);
    	for(i=1;i^n;++i) F.writeln(c[i]>sn?T.BF(b[i],b[i+1],c[i]):T.GetAns(b[i],b[i+1],c[i]));//设阈值
    	return F.clear(),0;
    }
    
  • 相关阅读:
    [android] 安卓消息推送的几种实现方式
    二进制部署 Kubernetes 集群
    nginx location反向代理不对等时的处理
    CentOS7用阿里云Docker Yum源在线安装Docker 17.03.2
    Harbor作为Docker的镜像中心
    Harbor 使用 Helm 一键安装
    MYSQL Innodb逻辑存储结构
    安装Redis 4.0单实例
    Redis慢查询日志
    创建Python数据分析的Docker镜像+Docker自定义镜像commit,Dockerfile方式解析+pull,push,rmi操作
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4381.html
Copyright © 2011-2022 走看看