JZOJ4843. 【GDOI2017模拟11.2】相位幻击
2016-11-14 21:05
288 查看
题目描述
分析
我们知道xor是可逆的,那么对于一个询问x,y,设lca是z,假如我们设val[i]为i到根的xor值,就可以知道val[x]^val[y]^val[father(z)]是答案嘛。另外,xor题一般的思路是先拆位。
那么对于某个节点我们要让他整颗子树原本的0,1状态掉转(xor 1),或者不动(xor 0)。现在考虑如何放到val上来:我们发现它子树的点跟他深度奇偶性相同的点val是不变的,而奇偶性不同的都翻转了。那这拿线段树以dfn为下标就很好维护了。
代码
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define fo(i,j,k) for(i=j;i<=k;i++) const int N=200005; struct rec { int tag; //int v; }; char ch; int b[N*2],next[N*2],first ,tt; int tr[2][N*4],fa [18],f[2] ,dis ,n,m,a ,st ,en ,t[2],x,y,i,j,l,dur,lc; void cr(int x,int y) { tt++; b[tt]=y; next[tt]=first[x]; first[x]=tt; } void swap(int &x,int &y) { int z=x; x=y; y=z; } void down(int ty,int x,int l,int r) { if (l!=r) { tr[ty][x*2]^=tr[ty][x]; tr[ty][x*2+1]^=tr[ty][x]; tr[ty][x]=0; } } void change(int ty,int x,int l,int r,int i,int j) { int m=(l+r)/2; down(ty,x,l,r); if (l==i&&r==j) { tr[ty][x]^=y; return; } if (m>=j) change(ty,x*2,l,m,i,j);else if (m<i) change(ty,x*2+1,m+1,r,i,j);else { change(ty,x*2,l,m,i,m); change(ty,x*2+1,m+1,r,m+1,j); } } int get(int ty,int x,int l,int r,int pos) { int m=(l+r)/2; down(ty,x,l,r); if (l==r) return f[ty][l]^tr[ty][x]; if (m>=pos) return get(ty,x*2,l,m,pos); else return get(ty,x*2+1,m+1,r,pos); } int lca(int x,int y) { if (dis[x]<dis[y]) swap(x,y); int i; if (dis[x]!=dis[y]) { i=trunc(log(double(dis[x]-dis[y]))/log(2)); while (i>=0) { while (i>=0&&dis[fa[x][i]]<dis[y]) i--; if (i==-1) break; x=fa[x][i]; i--; } } if (x==y) return x; i=trunc(log(double(dis[x]))/log(2)); while (i>=0) { while (i>=0&&fa[x][i]==fa[y][i]) i--; if (i==-1) break; x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } void dfs(int x,int y) { a[x]^=a[y]; fa[x][0]=y; dis[x]=dis[y]+1; int tmp=dis[x]%2; t[tmp]++; f[tmp][t[tmp]]=a[x]; st[x]=t[tmp]; for(int p=first[x];p;p=next[p]) if (b[p]!=y) dfs(b[p],x); en[x]=t[tmp]; } int F(int x) { if (!x) return 0; return get(dis[x]%2,1,1,t[dis[x]%2],st[x]); } int main() { freopen("phase.in","r",stdin); freopen("phase.out","w",stdout); scanf("%d",&n); fo(i,1,n-1) { scanf("%d%d",&x,&y); cr(x,y); cr(y,x); } fo(i,1,n) scanf("%d",a+i); dfs(1,0); fo(j,1,trunc(log((double)n)/log(2))) fo(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1]; scanf("%d\n",&m); fo(l,1,m) { scanf("%c %d %d\n",&ch,&x,&y); if (ch=='C') change(dis[x]%2,1,1,t[dis[x]%2],st[x],en[x]); else { lc=lca(x,y); dur=F(x)^ F(y)^ F(lc)^ F(fa[lc][0]); printf("%d\n",dur); } } }
思考
虽然一般来说,直接维护某个点到根的路径的信息大部分时候不优,但也有特殊情况,这道题就是一例,做题时,我们不能轻易略过某种思路,必须思考一下,也许会有转机。相关文章推荐
- 【GDOI2017模拟11.2】相位幻击
- 【GDOI2017模拟11.2】相位幻击
- JZOJ4844. 【GDOI2017模拟11.2】抗拒黄泉 背包合并相同状态优化容斥
- JZOJ 4295【NOIP2015模拟11.2】愉快的logo设计
- [JZOJ4695]【GDOI2017模拟8.14】佐助的难题
- JZOJ 4296【NOIP2015模拟11.2】有趣的有趣的家庭菜园
- JZOJ4769 【GDOI2017模拟9.9】graph CDQ分治+用按秩合并维护带撤销的并查集(BZOJ 4025)
- JZOJ 4863 【GDOI2017模拟11.5】Market
- 【jzoj4982】【GDOI2017模拟2.23】【加密】【sam】
- JZOJ4796 【GDOI2017模拟9.21】三色图 构造可行解
- JZOJ4849. 【GDOI2017模拟11.3】记忆的轮廓 期望+答案上界剪枝
- JZOJ 4863. 【GDOI2017模拟11.5】Market
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- 【GDOI2017模拟11.2】抗拒黄泉
- JZOJ4857. 【GDOI2017模拟11.4】Tourist Attractions
- JZOJ4779. 【GDOI2017模拟9.14】鞍点
- 【JZOJ4925】【GDOI2017模拟12.18】稻草人
- JZOJ4858. 【GDOI2017模拟11.4】Walk
- 【JZOJ4793】【GDOI2017模拟9.21】妮厨的愤怒
- 【JZOJ5324】【GDOI2017模拟8.21】麻将堆