BZOJ4811 Ynoi2017由乃的OJ(树链剖分+线段树)
先考虑NOI2014的水题,显然从高位到低位贪心,算一下该位取0和1分别得到什么即可。
加强这个水题,变成询问区间。那么线段树维护该位取0和1从左到右和从右到左走完这个节点表示的区间会变成什么即可,也滋磁修改了。
然后上树,显然树剖即可。非常惨的变成了O(nklog2n)。压一下位就不惨了,变成O(n(k+log2n))。
树剖lca都能写挂调一天,不会熟练剖分,退役了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll unsigned long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} ll read() { ll x=0;char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x; } ll b[N],gor[N<<2][2],gol[N<<2][2],inf,I; int n,m,k,a[N],p[N],t,cnt; int id[N],dfn[N],top[N],fa[N],son[N],size[N],deep[N]; int L[N<<2],R[N<<2]; struct data{int to,nxt; }edge[N<<1]; struct data2{ll x,y;}; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k]) { fa[edge[i].to]=k; deep[edge[i].to]=deep[k]+1; dfs(edge[i].to); size[k]+=size[edge[i].to]; if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to; } } void dfs2(int k,int from) { top[k]=from;dfn[k]=++cnt;id[cnt]=k; if (son[k]) dfs2(son[k],from); for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k]&&edge[i].to!=son[k]) dfs2(edge[i].to,edge[i].to); } ll trans1(ll x,int op,ll y){if (op==1) return x&y;if (op==2) return x|y;return x^y;} ll trans(ll x,ll t0,ll t1){return (x&t1)|((~x)&t0);} void up(int k) { gor[k][0]=trans(gor[k<<1][0],gor[k<<1|1][0],gor[k<<1|1][1]); gor[k][1]=trans(gor[k<<1][1],gor[k<<1|1][0],gor[k<<1|1][1]); gol[k][0]=trans(gol[k<<1|1][0],gol[k<<1][0],gol[k<<1][1]); gol[k][1]=trans(gol[k<<1|1][1],gol[k<<1][0],gol[k<<1][1]); } void build(int k,int l,int r) { L[k]=l,R[k]=r; if (l==r) {gol[k][0]=gor[k][0]=trans1(0,a[id[l]],b[id[l]]);gol[k][1]=gor[k][1]=trans1(inf,a[id[l]],b[id[l]]);return;} int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); up(k); } void modify(int k,int x,int op,ll y) { if (L[k]==R[k]) {gol[k][0]=gor[k][0]=trans1(0,op,y);gol[k][1]=gor[k][1]=trans1(inf,op,y);return;} int mid=L[k]+R[k]>>1; if (x<=mid) modify(k<<1,x,op,y); else modify(k<<1|1,x,op,y); up(k); } data2 queryl(int k,int l,int r) { if (L[k]==l&&R[k]==r) return (data2){gol[k][0],gol[k][1]}; int mid=L[k]+R[k]>>1; if (r<=mid) return queryl(k<<1,l,r); else if (l>mid) return queryl(k<<1|1,l,r); else { data2 x=queryl(k<<1|1,mid+1,r),y=queryl(k<<1,l,mid); return (data2){trans(x.x,y.x,y.y),trans(x.y,y.x,y.y)}; } } data2 queryr(int k,int l,int r) { if (L[k]==l&&R[k]==r) return (data2){gor[k][0],gor[k][1]}; int mid=L[k]+R[k]>>1; if (r<=mid) return queryr(k<<1,l,r); else if (l>mid) return queryr(k<<1|1,l,r); else { data2 x=queryr(k<<1,l,mid),y=queryr(k<<1|1,mid+1,r); return (data2){trans(x.x,y.x,y.y),trans(x.y,y.x,y.y)}; } } void solve(ll &t0,ll &t1,int x,int lca) { if (top[x]==top[lca]) { data2 t=queryr(1,dfn[lca],dfn[x]); t0=trans(t0,t.x,t.y),t1=trans(t1,t.x,t.y); return; } solve(t0,t1,fa[top[x]],lca); data2 t=queryr(1,dfn[top[x]],dfn[x]); t0=trans(t0,t.x,t.y),t1=trans(t1,t.x,t.y); } ll jump_query(int x,int y,ll z) { ll t0=0,t1=inf;data2 t;int lca=0,P=x,Q=y; while (top[P]!=top[Q]) { if (deep[top[P]]<deep[top[Q]]) swap(P,Q); P=fa[top[P]]; } if (deep[P]<deep[Q]) swap(P,Q); lca=Q; while (top[x]!=top[lca]) { t=queryl(1,dfn[top[x]],dfn[x]); t0=trans(t0,t.x,t.y),t1=trans(t1,t.x,t.y); x=fa[top[x]]; } if (lca!=x) { for (int i=p[lca];i;i=edge[i].nxt) if (dfn[edge[i].to]>dfn[lca]&&dfn[edge[i].to]<=dfn[x]) {t=queryl(1,dfn[edge[i].to],dfn[x]);break;} t0=trans(t0,t.x,t.y),t1=trans(t1,t.x,t.y); } solve(t0,t1,y,lca); ll s=0,c=0; for (int i=k-1;~i;i--) if (t0&(I<<i)) s+=I<<i; else if ((t1&(I<<i))&&c+(I<<i)<=z) c+=I<<i,s+=I<<i; return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4811.in","r",stdin); freopen("bzoj4811.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),k=read();inf=I=1;for (int i=1;i<=k;i++) inf<<=1;inf--; for (int i=1;i<=n;i++) a[i]=read(),b[i]=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } dfs(1); dfs2(1,1); build(1,1,n); while (m--) { int op=read(),x=read(),y=read();ll z=read(); if (op==1) printf("%llu\n",jump_query(x,y,z)); else modify(1,dfn[x],y,z); } return 0; }