[SCOI2016]幸运数字
题解:
想找到树剖的题写写,然后就找到了这么一题
树剖+线段树+线性基显然
分析一下复杂度就上天了 $nlog^2*60^2$
不过树剖的log我忽略一下。。线性基合并肯定跑不满假设只有60.。
差不多还可以跑跑
于是就写了,然后竟然过了
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for(int i=h;i<=t;i++) #define dep(i,t,h) for(int i=t;i>=h;i--) #define ll long long #define me(x) memset(x,0,sizeof(x)) #define mep(x,y) memcpy(x,y,sizeof(y)) #define mid ((h+t)>>1) namespace IO{ char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T> void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } char sr[1<<24],z[20]; int Z,C1=-1; template<class T>void wer(T x) { if (x<0) sr[++C1]='-',x=-x; while (z[++Z]=x%10+48,x/=10); while (sr[++C1]=z[Z],--Z); } IL void wer1() { sr[++C1]=' '; } IL void wer2() { sr[++C1]='\n'; } template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;} template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} template<class T>IL T MAX(T x,T y){return x>y?x:y;} template<class T>IL T MIN(T x,T y){return x<y?x:y;} }; using namespace IO; const int N=2.1e4; const int N1=N*4; ll v[N]; int head[N],l,dep[N],dy[N],son[N],dfn[N],cnt,num[N],fa[N]; int top[N],n,m,q; struct re{ int a,b; }e[N*2]; IL void arr(int x,int y) { e[++l].a=head[x]; e[l].b=y; head[x]=l; } void dfs1(int x,int y) { num[x]=1; dep[x]=dep[y]+1; fa[x]=y; for (rint u=head[x];u;u=e[u].a) { int v=e[u].b; if (v!=y) { dfs1(v,x); num[x]+=num[v]; if (num[v]>num[son[x]]) son[x]=v; } } } void dfs2(int x,int t,int y) { top[x]=t; dfn[x]=++cnt; dy[cnt]=x; if (son[x]) dfs2(son[x],t,x); for (rint u=head[x];u;u=e[u].a) { int v=e[u].b; if (v!=y&&v!=son[x]) dfs2(v,v,x); } } struct re2{ ll a[61]; re2() {me(a);} }; vector<re2> ve; struct sgt{ ll now[N1][61]; IL re2 hb(ll *x,ll *y) { re2 ans; int cnt1=0,cnt2=0; rep(i,0,60) if (x[i]) cnt1++; rep(i,0,60) if (y[i]) cnt2++; if (cnt1>cnt2) swap(x,y); rep(i,0,60) ans.a[i]=y[i]; rep(i,0,60) if (x[i]) { ll k=x[i]; dep(j,60,0) { if (!k) break; if ((k>>j)&1) if (ans.a[j]) k^=ans.a[j]; else { ans.a[j]=k; break; } } } return ans; } void build(int x,int h,int t) { if (h==t) { dep(i,60,0) if ((v[dy[h]]>>i)&1) { now[x][i]=v[dy[h]]; break; } return; } build(x*2,h,mid); build(x*2+1,mid+1,t); re2 p=hb(now[x*2],now[x*2+1]); memcpy(now[x],p.a,sizeof(p.a)); } void query(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) { re2 p; memcpy(p.a,now[x],sizeof(now[x])); ve.push_back(p); return; } if (h1<=mid) query(x*2,h,mid,h1,t1); if (mid<t1) query(x*2+1,mid+1,t,h1,t1); } ll query2(int x,int y) { ve.clear(); int f1=top[x],f2=top[y]; while (f1!=f2) { if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); query(1,1,n,dfn[f1],dfn[x]); x=fa[f1]; f1=top[x]; } if (dep[x]<dep[y]) swap(x,y); query(1,1,n,dfn[y],dfn[x]); int l=(int)(ve.size())-1; re2 p; rep(i,0,l) p=hb(p.a,ve[i].a); ll now=0; dep(i,60,0) if (p.a[i]&&!((now>>i)&1)) { now^=p.a[i]; } return now; } }S; int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(q); rep(i,1,n) read(v[i]); rep(i,1,n-1) { int x,y; read(x); read(y); arr(x,y); arr(y,x); } dfs1(1,0); dfs2(1,1,0); S.build(1,1,n); rep(i,1,q) { int x,y; read(x); read(y); wer(S.query2(x,y)); wer2(); } fwrite(sr,1,C1+1,stdout); return 0; }
当然感觉是数据并不强的原因。。
然而这题用倍增+线性基$nlog^3$的复杂度 也就比树剖快了一倍
线性基合并可以有点常数优化见我的代码 看下面
当然这题是有$nlog^2n$的做法的
既然离线我们利用点分治
然后把lca等于rt的放在现在计算
点分治的一个常数优化是对n<=k的时候进行暴力计算
但这题里效果应该并不明显
另外上面那个线性基合并写的太菜了。。
现在的这个比那个少算了100倍???(实测一个线性基循环3e7 一个1e5)
优化1:为0直接跳
优化2:从当前位往下
优化3:维护最低位
也就是说线性基合并基本没花时间。。 时间在于插入线性基
然后把插入线性基也这么优化一下
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (int i=h;i<=t;i++) #define dep(i,t,h) for (int i=t;i>=h;i--) #define me(x) memset(x,0,sizeof(x)) #define ll long long #define mep(x,y) memcpy(x,y,sizeof(y)) namespace IO{ char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T>void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } char sr[1<<24],z[20]; int Z,C=-1; template<class T>void wer(T x) { if (x<0) sr[++C]='-',x=-x; while (z[++Z]=x%10+48,x/=10); while (sr[++C]=z[Z],--Z); } IL void wer1() { sr[++C]=' ';} IL void wer2() { sr[++C]='\n';} template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;} template<class T>IL void mina(T &x,T y) { if (x>y) x=y;} template<class T>IL T MAX(T x,T y) {return x>y?x:y;} template<class T>IL T MIN(T x,T y) {return x<y?x:y;} }; using namespace IO; const int N=3e5; bool vis[N]; int head[N],l,num[N],f[N],rt,col[N],all,pos[N],jl[N]; ll now[N][61],p[N][61],ans[N],v[N]; struct re{ int a,b,c; }e[N*2],a[N]; vector<re>ve[N]; IL void arr(int x,int y) { e[++l].a=head[x]; e[l].b=y; head[x]=l; } struct re2{ ll a[61]; re2() {me(a);} }; int cnt2=0,cnt3=0; IL re2 hb(ll *x,ll *y) { cnt2++; re2 ans; rep(i,0,60) { if (y[i]) ans.a[i]=y[i]; else ans.a[i]=x[i]; } int A; for(A=0;A<=60;A++) if (!ans.a[A]) break; rep(i,0,60) if (x[i]&&y[i]) { ll k=x[i]; dep(j,i,A) { cnt3++; if (!k) break; if ((k>>j)&1) if (ans.a[j]) k^=ans.a[j]; else { ans.a[j]=k; break; } if (j==A) { for (;A<=60;A++) if (!ans.a[A]) break; } } } return ans; } void fdr(int x,int y) { num[x]=1; f[x]=0; for (rint u=head[x];u;u=e[u].a) { int v=e[u].b; if (v!=y&&!vis[v]) { fdr(v,x); num[x]+=num[v]; if (num[v]>f[x]) f[x]=num[v]; } } if (all-num[x]>f[x]) f[x]=all-num[x]; if (f[x]<f[rt]) rt=x; } IL void ins(ll *x,ll y,int z,int &k) { dep(i,z,k) { if (!y) return; if ((y>>i)&1) if (x[i]) y^=x[i]; else { x[i]=y; break; } } while (x[k]) k++; } void dfs(int x,int y,int color) { mep(p[x],p[y]); jl[x]=jl[y]; ins(p[x],v[x],pos[x],jl[x]); col[x]=color; for (rint u=head[x];u;u=e[u].a) { int v=e[u].b; if (v!=y&&!vis[v]) dfs(v,x,color); } } int cnt=0; void dfz(int x,int y) { all=num[x]; rt=0; f[x]=0; fdr(x,0); mep(p[rt],now[rt]); jl[rt]=0; for(rint u=head[rt];u;u=e[u].a) { int v=e[u].b; if (!vis[v]) dfs(v,rt,++cnt); } int l=(int)(ve[y].size())-1; rep(i,0,l) { int x1=ve[y][i].a,x2=ve[y][i].b; if (col[x1]!=col[x2]||x1==rt) { re2 o=hb(p[x1],p[x2]); ll now=0; dep(i,60,0) if (o.a[i]&&!((now>>i)&1)) { now^=o.a[i]; } ans[ve[y][i].c]=now; } else ve[col[x1]].push_back(ve[y][i]); } vis[rt]=1; for (rint u=head[rt];u;u=e[u].a) { int v=e[u].b; if (!vis[v]) dfz(v,col[v]); } } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); f[0]=1e9; int n,m; read(n); read(m); rep(i,1,n) { read(v[i]); dep(j,60,0) if ((v[i]>>j)&1) { now[i][j]=v[i]; pos[i]=j; break; } } rep(i,1,n-1) { int x,y; read(x); read(y); arr(x,y); arr(y,x); } rep(i,1,m) { read(a[i].a),read(a[i].b),a[i].c=i; ve[1].push_back(a[i]); } num[1]=n; cnt=1; dfz(1,1); rep(i,1,m) wer(ans[i]),wer2(); fwrite(sr,1,C+1,stdout); return 0; }