[bzoj2589]Count on a tree II

编程入门 行业动态 更新时间:2024-10-28 02:36:14

[bzoj2589]<a href=https://www.elefans.com/category/jswz/34/1759757.html style=Count on a tree II"/>

[bzoj2589]Count on a tree II

Count on a tree II

题解

看到这道题,如果不加强制在线什么的,应该是很容易想到树上莫队的,根据欧拉序很容易解决。

可是由于要强制在线,就不能离线下来做了,于是我们就想到了用树上分块来进行处理。

容易证明,如果我们在一棵节点数为的树上选择一些点使得树上任意一点到被选择点的距离不会超过,那么一定存在一种方法使得选择的点数不会超过个。

如果我们从深度最大且未被覆盖的点开始,往上找最多个点,将最远处即与那个点距离达到的祖先或是根节点的点选择,则一定可以使当前的选择成为这个点子树上的最优解,因为其子树上不会存在点的贡献比它大。

于是,我们就可以先这样选出个点,将被选择的点两点中间的用bitset维护颜色。这样的话预处理出每个被选择的点到其祖先中的被选择的点的时间复杂度是的,更新并查集还有个。

查询的时候就先将两点到其祖先中最近的选择点的距离上的贡献给暴力跑出来,在从选择的点一段一段的更新,最后到两者lca的那一段距离再暴力更新,当然,如果两者的路径间根本没有点被选择直接暴力跑就行了。这样查询的时间复杂度是的。好难看呀

总时间复杂度。特难看。

可以发现,其实最优时为的样子,时间复杂度为。不过实际数据检测,还是可以取大点。

源码

用重链剖分的方式跑lca好像比倍增快些,不过笔者还是放二点倍增版本。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 40005
typedef long long LL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
int n,m,val[MAXN],b[MAXN],cnt,head[MAXN],tot;
int f[MAXN][22],mxd[MAXN],dep[MAXN];
int father[MAXN],sta[MAXN],stak,id[MAXN],idx;
int ltp[MAXN],ff[MAXN],las;
bitset<MAXN>bt[45][45],now;
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dfs(int u,int fa){mxd[u]=dep[u]=dep[fa]+1;f[u][0]=father[u]=fa;for(int i=1;i<21;i++)f[u][i]=f[f[u][i-1]][i-1];for(int i=head[u];i;i=e[i].nxt){int v=e[i].to;if(v==fa)continue;dfs(v,u);mxd[u]=max(mxd[u],mxd[v]);}if(mxd[u]-dep[u]>=1000)id[u]=++idx,mxd[u]=dep[u];
}
void dfs2(int u,int fa){for(int i=head[u];i;i=e[i].nxt){int v=e[i].to;if(v==fa)continue;if(id[v]){int ip=id[sta[stak]],in=id[v];for(int j=v;j!=sta[stak];j=father[j])bt[ip][in].set(val[j]);now=bt[ip][in];for(int j=1;j<stak;j++){bitset<MAXN>&bs=bt[id[sta[j]]][in];bs=bt[id[sta[j]]][ip];bs|=now; }ff[v]=sta[stak];sta[++stak]=v;}dfs2(v,u);if(id[v])stak--;}
} 
int lca(int a,int b){if(dep[a]<dep[b])swap(a,b);for(int i=20;i>=0;i--)if(dep[f[a][i]]>=dep[b])a=f[a][i];if(a==b)return a;for(int i=20;i>=0;i--)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];return f[a][0];
}
signed main(){read(n);read(m);for(int i=1;i<=n;i++)read(val[i]),b[++cnt]=val[i];sort(b+1,b+cnt+1);cnt=unique(b+1,b+cnt+1)-b-1;for(int i=1;i<=n;i++)val[i]=lower_bound(b+1,b+cnt+1,val[i])-b;for(int i=1;i<n;i++){int u,v;read(u);read(v);addEdge(u,v);addEdge(v,u);}dfs(1,0);if(!id[1])id[1]=++idx;sta[++stak]=1;dfs2(1,0);while(m--){int u,v;read(u);read(v);now.reset();u^=las;int u_v=lca(u,v);while(u!=u_v&&!id[u])now.set(val[u]),u=father[u];while(v!=u_v&&!id[v])now.set(val[v]),v=father[v];//printf("%d %d %d %d %d\n",u,v,id[u],id[v],u_v);if(u!=u_v){int pre=u;while(dep[ff[pre]]>=dep[u_v])pre=ff[pre];if(pre!=u)now|=bt[id[pre]][id[u]];while(pre!=u_v)now.set(val[pre]),pre=father[pre];}if(v!=u_v){int pre=v;while(dep[ff[pre]]>=dep[u_v])pre=ff[pre];if(pre!=v)now|=bt[id[pre]][id[v]];while(pre!=u_v)now.set(val[pre]),pre=father[pre];}now.set(val[u_v]);printf("%d\n",las=now.count());}return 0;
}

谢谢!!!

更多推荐

[bzoj2589]Count on a tree II

本文发布于:2024-02-17 05:02:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1692751.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Count   II   tree

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!