bzoj 4568 [SCOI 2016] 幸运数字
2017-07-10 12:54
344 查看
题目大意
给定一棵\(n\)个点的树,每个点有权值\(q\)次询问树上路径中
每个点权值可选可不选的最大异或和
\(n\le 2*10^4,q\le 2*10^5,val[i]\le 2^{60}\)
分析
线性基但数据范围不太对啊woc
两线性基合并\(O(60^2)\)
如果 树剖+线性基 则\(O(q\log^2n ~60^2)\)
如果 树上倍增+线性基 则是一个常数较大的\(O(q\log n~60^2)\)
不是很妙啊
做法1
注意到,这不是常规的树上询问,因为是异或(线性基)线性基同一个值重复插入时没有问题的
即树上某一段算重是可以的
那么我们可以这样算
其中橙色部分时一个长度\(2^k\)的段
这样就只用统计\(4\)次了
复杂度\(O(4*60^2~q)\)
做法2
点分治求出重心到每个点的线性基\(O(60n)\)
然后解决询问
如果询问与该重心有关,单次\(O(60^2)\)
否则将该询问传到儿子
点分每层扫过的询问数\(O(q)\)的
总复杂度
\(O(60n\log n~+~q \log n~+~60^2 q)\)
solution 1
#include <cstring> #include <cstdio> #include <cstdlib> #include <cctype> #include <cmath> #include <algorithm> using namespace std; const int M=2e4+7; const int B=60; typedef long long LL; inline int rd(){ int x=0;bool f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=0; for(;isdigit(c);c=getchar()) x=x*10+c-48; return f?x:-x; } inline LL lrd(){ LL x=0;bool f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=0; for(;isdigit(c);c=getchar()) x=x*10+c-48; return f?x:-x; } struct vec{ int g[M],te; struct edge{ int y,nxt; edge(int _y=0,int _nxt=0){ y=_y,nxt=_nxt; } }e[M<<1]; vec(){memset(g,0,sizeof g);te=0;} inline void push(int x,int y){e[++te]=edge(y,g[x]);g[x]=te;} inline void push2(int x,int y){push(x,y);push(y,x);} inline int& operator () (int x){return g[x];} inline edge& operator [] (int x){return e[x];} }e; struct Base{ LL a[B+3]; Base(){memset(a,0,sizeof a);} void ins(LL x){ for(int i=B;i>=0;i--) if(x>>i&1){ if(a[i]) x^=a[i]; else {a[i]=x;return;} } } LL getmx(){ LL res=0; int i; for(i=B;i>=0;i--) if((res^a[i])>res) res^=a[i]; return res; } friend Base merge(const Base &x,const Base &y){ Base res; int i; for(i=B;i>=0;i--) if(x.a[i]) res.ins(x.a[i]); for(i=B;i>=0;i--) if(y.a[i]) res.ins(y.a[i]); return res; } friend Base merge(const Base &x,const LL &y){ Base res=x; res.ins(y); return res; } }; int n,m,D; LL val[M]; int dep[M]; int pre[M][15]; Base f[M][15]; void dfs(int x){ int p,y; for(p=e(x);p;p=e[p].nxt) if((y=e[p].y)!=pre[x][0]){ dep[y]=dep[x]+1; pre[y][0]=x; f[y][0].ins(val[y]); dfs(y); } } void init(){ D=(int)log2(n); int i,j; for(j=1;j<=D;j++) for(i=1;i<=n;i++){ pre[i][j]=pre[pre[i][j-1]][j-1]; f[i][j]=merge(f[i][j-1],f[pre[i][j-1]][j-1]); } } int LCA(int x,int y){ int i; if(dep[x]<dep[y]) swap(x,y); for(i=D;i>=0;i--) if(dep[pre[x][i]]>=dep[y]) x=pre[x][i]; if(x==y) return x; for(i=D;i>=0;i--) if(pre[x][i]!=pre[y][i]) x=pre[x][i],y=pre[y][i]; return pre[x][0]; } int jp(int x,int kth){ for(int i=D;i>=0;i--) if(kth>>i&1) x=pre[x][i]; return x; } Base calc(int x,int to){ for(int i=D;i>=0;i--) if(dep[pre[x][i]]>=dep[to]){ int y=jp(x,dep[pre[x][i]]-dep[to]); return merge(f[x][i],f[y][i]); } return Base(); } LL get(int x,int y){ Base res; int lca=LCA(x,y),i; res=merge(merge(calc(x,lca),calc(y,lca)),val[lca]); return res.getmx(); } int main(){ int i,x,y; n=rd(),m=rd(); for(i=1;i<=n;i++) val[i]=lrd(); for(i=1;i<n;i++) e.push2(rd(),rd()); pre[1][0]=0; dep[1]=1; dfs(1); init(); for(i=1;i<=m;i++){ x=rd(),y=rd(); printf("%lld\n",get(x,y)); } return 0; }
solution 2
#include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <algorithm> using namespace std; const int N=2e5+7; const int M=2e4+7; const int B=60; typedef long long LL; inline int ri(){ int x=0;bool f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=0; for(;isdigit(c);c=getchar()) x=x*10+c-48; return f?x:-x; } inline LL rl(){ LL x=0;bool f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=0; for(;isdigit(c);c=getchar()) x=x*10+c-48; return f?x:-x; } struct vec{ int g[M],te; struct edge{ int y,nxt; edge(int _y=0,int _nxt=0){y=_y,nxt=_nxt;} }e[M<<1]; vec(){memset(g,0,sizeof g);te=0;} inline void push(int x,int y){e[++te]=edge(y,g[x]);g[x]=te;} inline void push2(int x,int y){push(x,y);push(y,x);} inline int& operator () (int x){return g[x];} inline edge& operator [] (int x){return e[x];} }e; struct vec2{ int g[M],te; struct ques{ int x,y,id,nxt; ques(int _x=0,int _y=0,int _id=0,int _nxt=0){x=_x,y=_y,id=_id,nxt=_nxt;} }e[N*17]; vec2(){memset(g,0,sizeof g);te=0;} inline void push(int u,int x,int y,int id){e[++te]=ques(x,y,id,g[u]);g[u]=te;} inline int& operator () (int x){return g[x];} inline ques& operator [] (int x){return e[x];} }ask; struct Base{ LL a[B+3]; Base(){memset(a,0,sizeof a);} void clear(){memset(a,0,sizeof a);} void ins(LL x){ for(int i=B;i>=0;i--) if(x>>i&1){ if(a[i]) x^=a[i]; else {a[i]=x;break;} } } LL getmx(){ LL res=0; for(int i=B;i>=0;i--) if((res^a[i])>res) res^=a[i]; return res; } friend Base merge(const Base &x,const Base &y){ Base res; for(int i=B;i>=0;i--) if(x.a[i]) res.ins(x.a[i]); for(int i=B;i>=0;i--) if(y.a[i]) res.ins(y.a[i]); return res; } friend Base merge(const Base &x,const LL &y){ Base res=x; res.ins(y); return res; } }; int n,m; LL val[M]; int sz[M]; int mi,size,rt; bool vis[M]; int bl[M]; LL ans ; Base f[M]; LL calc(int x,int y){ Base res=merge(f[x],f[y]); return res.getmx(); } void getsz(int x,int fa){ sz[x]=1; int p,y; for(p=e(x);p;p=e[p].nxt) if((y=e[p].y)!=fa&&!vis[y]){ getsz(y,x); sz[x]+=sz[y]; } } void getrt(int x,int fa){ int f=size-sz[x],p,y; for(p=e(x);p;p=e[p].nxt) if((y=e[p].y)!=fa&&!vis[y]){ getrt(y,x); f=max(f,sz[y]); } if(f<mi) mi=f,rt=x; } void dfs(int x,int fa){ f[x]=merge(f[fa],val[x]); int p,y; for(p=e(x);p;p=e[p].nxt) if((y=e[p].y)!=fa&&!vis[y]) bl[y]=bl[x],dfs(y,x); } void work(int fr){ getsz(fr,0); mi=size=sz[fr]; getrt(fr,0); int x=rt,i,p,y; vis[x]=1; bl[x]=x; f[x].clear(); f[x].ins(val[x]); if(x!=fr) {ask(x)=ask(fr); ask(fr)=0;}// for(p=e(x);p;p=e[p].nxt) if(!vis[y=e[p].y]){ bl[y]=y; dfs(y,x); } for(p=ask(x);p;p=ask[p].nxt){ if(bl[ask[p].x]==bl[ask[p].y]) ask.push(bl[ask[p].x],ask[p].x,ask[p].y,ask[p].id); else ans[ask[p].id]=calc(ask[p].x,ask[p].y); } for(p=e(x);p;p=e[p].nxt) if(!vis[y=e[p].y]) work(y); } int main(){ int i,x,y; n=ri(),m=ri(); for(i=1;i<=n;i++) val[i]=rl(); for(i=1;i<n;i++) e.push2(ri(),ri()); for(i=1;i<=m;i++){ x=ri(), y=ri(); if(x==y) ans[i]=val[x]; else ask.push(1,x,y,i); } work(1); for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- BZOJ 4568 [Scoi2016]幸运数字 ——线性基 倍增
- bzoj 4568: [Scoi2016]幸运数字【树链剖分+线段树+线性基】
- BZOJ 4568 [Scoi2016]幸运数字 【倍增线性基
- [BZOJ]4568 [SCOI2016] 幸运数字 线性基合并
- bzoj 4568: [Scoi2016]幸运数字
- bzoj 4568: [Scoi2016]幸运数字 倍增维护线性基
- BZOJ4568: [Scoi2016]幸运数字【线性基】
- bzoj 4568: [Scoi2016]幸运数字
- 【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)
- bzoj 4568: [Scoi2016]幸运数字 (高斯消元求解线性基)
- BZOJ4568 [Scoi2016]幸运数字
- BZOJ 4568: [Scoi2016]幸运数字
- bzoj 4568 [Scoi2016]幸运数字 倍增+线性基
- 【BZOJ 4568】[Scoi2016]幸运数字
- BZOJ 4568: [Scoi2016]幸运数字 [线性基 倍增]
- BZOJ 4568: [Scoi2016]幸运数字
- [线性基 树链剖分 线段树 || ST表 || 点分治] BZOJ 4568 [Scoi2016]幸运数字
- [BZOJ]4568: [Scoi2016]幸运数字 倍增+线性基
- BZOJ 4568 [Scoi2016]幸运数字
- 4568: [Scoi2016]幸运数字