bzoj2908
题解:
我的做法好像跟网上不太一样。。
首先分位讨论
我的做法是先观察出了一个性质
这个答案只跟最后一个0出现的位置有关(这个随便yy一下很容易出来因为运算有0则1)
然后问题就变成了
给出一棵树,支持单点修改,查询x向上第一个0的位置
其实这个用lct维护比较方便。。而且这个复杂度是nlog^2的 我有空写下比较一下时间。。
我写的是nlog^3的树剖维护。。注意到路径有向所以还要分情况分开写(第一次写)
所以lct写起来应该非常简单。。。。除了updata改改其他就是模板了。。
主要是这段时间在做线段树没想lct。。。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define IL inline #define rint register int #define mid ((h+t)/2) #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) char ss[1<<27],*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(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } void read2(char* x) { string s; char c; while (c=gc(),c!=' ') s+=c; strcpy(x,s.c_str()); } char sr[1<<24],z[20]; int C=-1,Z; 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); sr[++C]='\n'; } IL int max(int x,int y) { if (x>y) return(x); else return(y); } IL int min(int x,int y) { if (x<y) return(x); else return(y); } IL void swap(int &x,int &y) { int tmp=x; x=y; y=tmp; } IL bool odd(int x) { if (x%2==1) return(1); else return(0); } const int N=1.1e5; char s[20]; int l,head[N],v[N],fa[N],son[N],size[N],dfn[N],top[N],real2[N],dep[N],num,n,m,k; struct re{ int a,b,c; }a[N*2]; void arr(int x,int y) { a[++l].a=head[x]; a[l].b=y; head[x]=l; } void dfs1(int x,int y) { fa[x]=y; size[x]=1; son[x]=0; dep[x]=dep[y]+1; int u=head[x]; while (u) { int v=a[u].b; if (v!=y) { dfs1(v,x); size[x]+=size[v]; if (size[v]>size[son[x]]) son[x]=v; } u=a[u].a; } } void dfs2(int x,int y) { dfn[x]=++num; real2[num]=x; top[x]=y; if(!son[x]) return; dfs2(son[x],y); int u=head[x]; while (u) { int v=a[u].b; if (v!=fa[x]&&v!=son[x]) dfs2(v,v); u=a[u].a; } } struct sgt{ int f[N*4]; sgt() { rep(i,0,N*4-1) f[i]=1; } IL void updata(int x) { f[x]=f[x*2]&f[x*2+1]; } void insert(int x,int h,int t,int pos,int k) { if (h==t) { f[x]=k; return; } if (pos<=mid) insert(x*2,h,mid,pos,k); else insert(x*2+1,mid+1,t,pos,k); updata(x); } vector<re> ve; void query5(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) { ve.push_back((re){x,h,t}); return; } if (h1<=mid) query5(x*2,h,mid,h1,t1); if (mid<t1) query5(x*2+1,mid+1,t,h1,t1); } int query3(int x,int h,int t) { if (h==t) return(real2[h]); if (!f[x*2]) return(query3(x*2,h,mid)); else return(query3(x*2+1,mid+1,t)); } int query4(int x,int h,int t) { if (h==t) return(real2[h]); if (!f[x*2+1]) return(query4(x*2+1,mid+1,t)); else return(query4(x*2,h,mid)); } int query1(int x,int h,int t,int h1,int t1) { ve.clear(); query5(x,h,t,h1,t1); dep(i,ve.size()-1,0) if (!f[ve[i].a]) return(query4(ve[i].a,ve[i].b,ve[i].c)); return(-1); } int query2(int x,int h,int t,int h1,int t1) { ve.clear(); query5(x,h,t,h1,t1); rep(i,0,ve.size()-1) if (!f[ve[i].a]) return(query3(ve[i].a,ve[i].b,ve[i].c)); return(-1); } int query(int x,int y) { int x1=x,x2,x3=y; vector<re> v1,v2; int f1=top[x],f2=top[y]; while (f1!=f2) { if (dep[f1]<dep[f2]) { v2.push_back((re){y,f2}); y=fa[f2]; f2=top[y]; } else { v1.push_back((re){x,f1}); x=fa[f1]; f1=top[x]; } } if (dep[x]<dep[y]) v2.push_back((re){y,x}),x2=x; else v1.push_back((re){x,y}),x2=y; rint ans; // rep(i,0,(v1.size()-1)) for (int i=0;i<v1.size();i++) { ans=query1(1,1,n,dfn[v1[i].b],dfn[v1[i].a]); if (ans!=-1) return(!odd(dep[x1]-dep[ans])); } for (int i=v2.size()-1;i>=0;i--) { ans=query2(1,1,n,dfn[v2[i].b],dfn[v2[i].a]); if (ans!=-1) return(!odd(-2*dep[x2]+dep[x1]+dep[ans])); } return(!odd(dep[x1]+dep[x3]-2*dep[x2])); } }sgt[33]; int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); read(k); 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); rep(i,0,k-1) rep(j,1,n) sgt[i].insert(1,1,n,dfn[j],(v[j]>>i)&1); rep(i,1,m) { int x,y; read2(s); read(x); read(y); if (s[0]=='Q') { ll ans=0; rep(j,0,k-1) ans+=1ll*sgt[j].query(y,x)*(1ll<<j); wer(ans); } else { rep(j,0,k-1) sgt[j].insert(1,1,n,dfn[x],(y>>j)&1); } } fwrite(sr,1,C+1,stdout); return 0; }
正解:
其实正解很简单啊。。。
首先分位讨论和我一样
然后每次进去只有0/1两种
所以直接上线段树就可以了
但是这样也是nlog^3的(比我写的这个应该要简单啊,不用线段树二分了)
我们考虑优化一下
我们把进去的状态加一个 (1<<k)-1(这个还是非常巧妙的)
我们需要进去的时候对(1<<k)-1 的值and一下 因为只有两个都为1之后才会为1
而对于0的值我们需要取反再and
这样就做到了nlog^2(这个一定是可以碾压lct的)