线性基+树链剖分(bzoj4568)
来源:互联网 发布:淘宝换货售后卡怎么写 编辑:程序博客网 时间:2024/04/25 18:59
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=20005;const int m_base=60;ll read(){ long long x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f;}struct Base{ ll a[m_base+1]; Base() { memset(a,0,sizeof(a)); }};void add(Base &y,ll x)/*生成一组线性基*/{ for(int i=m_base;~i;i--) { if((x>>i)&1) { if(y.a[i]) x^=y.a[i]; else { y.a[i]=x; break; } } }}int siz[N],top[N],son[N],dep[N],tid[N],rk[N],fa[N];//siz[]数组,用来保存以x为根的子树节点个数//top[]数组,用来保存当前节点的所在链的顶端节点//son[]数组,用来保存重儿子//dep[]数组,用来保存当前节点的深度//fa[]数组,用来保存当前节点的父亲//tid[]数组,用来保存树中每个节点剖分后的新编号//rk[]数组,线段树中编号对应的原节点编号int cnt,tim;ll ac[N];struct node{ int next,to;} edge[N*2];int head[N];void intt(){ cnt=tim=0; memset(son,-1,sizeof(son)); memset(head,-1,sizeof(head));}void addedge(int u,int v){ edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}void dfs1(int u,int pre/*fa*/,int de){/*求出每个点的深度和父节点,和重儿子*/ dep[u]=de;fa[u]=pre;siz[u]=1; for(int i=head[u]; ~i; i=edge[i].next) { int v=edge[i].to; if(v!=pre) { dfs1(v,u,de+1); siz[u]+=siz[v]; if(son[u]==-1||siz[v]>siz[son[u]]) son[u]=v; } }}void dfs2(int u,int tp){/*给链编号,形成一一对应的关系*/ top[u]=tp; tid[u]=++tim; rk[tid[u]]=u; if(son[u]==-1) return; dfs2(son[u],tp); for(int i=head[u]; ~i; i=edge[i].next) { int v=edge[i].to; if(v!=son[u]/*不是u的重儿子*/&&v!=fa[u]/*不是u的父节点*/) dfs2(v,v); }}#define ls l,mid,rt<<1#define rs mid+1,r,rt<<1|1Base sum[4*N],ans;void up(int rt){ // sum[rt]=sum[rt<<1]; // for(int i=0;i<=m_base;i++) // if(sum[rt<<1|1].a[i]) // sum[rt].add(sum[rt<<1|1].a[i]); for(int i=m_base;i>=0;i--) sum[rt].a[i]=sum[rt<<1].a[i]; for(int i=m_base;i>=0;i--) if(sum[rt<<1|1].a[i]) add(sum[rt],sum[rt<<1|1].a[i]);}void build(int l,int r,int rt){ if(l==r) { sum[rt]=Base(); add(sum[rt],ac[rk[l]]); return; } int mid=(l+r)>>1; build(ls); build(rs); up(rt);}void query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) { for(int i=0;i<=m_base;i++) if(sum[rt].a[i]) add(ans,sum[rt].a[i]); return; } int mid=(l+r)>>1; if(mid>=L)query(L,R,ls); if(mid<R)query(L,R,rs);}/* 如果不在一条链上,那么比较x,y点链顶的父节点深度,更新深度深的链(进行交换,把深度深的赋予为x),更新完后,将范围调整到y--fa[top[x]],然后一直迭代,直到在同一个链上。 */int n,q;Base Change(int x,int y){ ans=Base(); while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); query(tid[top[x]],tid[x],1,n,1); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); query(tid[x],tid[y],1,n,1); return ans;}ll getmax(Base x){ ll tt=0; for(int i=m_base;~i;i--) if(((tt>>i)&1)==0&&x.a[i]) tt^=x.a[i]; return tt;}int main(){ n=read(),q=read(); intt(); for(int i=1;i<=n;i++) ac[i]=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); addedge(x,y); addedge(y,x); } dfs1(1,0,0); dfs2(1,1); build(1,n,1); for(int i=0;i<q;i++) { int aa=read(),bb=read(); printf("%lld\n",getmax(Change(aa,bb))); }}
阅读全文
0 0
- 线性基+树链剖分(bzoj4568)
- 【bzoj4568】[Scoi2016]幸运数字 线性基+树链剖分
- [BZOJ4568][Scoi2016]幸运数字 树链剖分+线性基
- BZOJ4568 [线性基][树链剖分][线段树]
- 【BZOJ4568】幸运数字,树链剖分/倍增+维护线性基
- [BZOJ4568][Scoi2016]幸运数字(高斯消元求线性基+lca+贪心)
- BZOJ4568: [Scoi2016]幸运数字【线性基】
- BZOJ4568 SCOI2016 幸运数字 倍增的思想维护线性基(线性基详解)
- 【bzoj4568】【SCOI2016】【幸运数字】【树上倍增+线性基】
- bzoj4568
- BZOJ4568 [Scoi2016]幸运数字
- bzoj4568: [Scoi2016]幸运数字
- bzoj4568【SCOI2016】幸运数字
- 【SCOI2016】bzoj4568 幸运数字
- BZOJ4568: [Scoi2016]幸运数字
- 线性基(草稿)
- bzoj2460(xor线性基)
- 线性基
- 17.读书笔记收获不止Oracle之 索引存储列值
- 2017年10月30日 第二十一次总结
- Failed to contact master at [localhost:11311]
- Git小结
- awk内置变量之OFMT、CONVFMT、RLENGTH、RSTART
- 线性基+树链剖分(bzoj4568)
- 序列标注模型和分类器标注模型区别
- 设计模式之观察者模式
- 【机器学习】神经网络及BP推导
- HDU
- PAT乙级题1020.月饼
- poj 1236 Network of Schools 强连通
- 设计模式之装饰者模式
- 正则