luogu2420 让我们异或和吧
2016-11-11 22:02
232 查看
题目
https://www.luogu.org/problem/show?pid=2420题解
小知识:异或xor 满足结合律、交换律。另外A xor A=0,也就是说A xor B xor C=E,那么B xor C = E xor A,也就是说可以前缀和。做法一:树链剖分,线段树维护。复杂度O(Nlog^2N)(注意坑点:因为权值在边上,所以交界处的值不能算进去)
做法二:树上前缀和,用s[x]表示根节点到x的路径上的权值异或值,那么两个点上路径的异或值就是s[a] xor s[b]。复杂度O(N+M)
做法三:LCT,把边化成点,然后瞎搞。代码老是TLE....我也没办法啊,毕竟常数大,暂且先这样吧
代码
//树链剖分 #include <cstdio> #include <algorithm> #define maxn 200010 using namespace std; int N, M, head[maxn], next[maxn], to[maxn], tmp[maxn], val[maxn], w[maxn], fa[maxn], size[maxn], son[maxn], tot, tim, deep[maxn], tid[maxn], top[maxn]; struct segtree { int l, r, w; segtree *lch, *rch; segtree(){w=0;lch=rch=0;} }*root; void adde(int a, int b, int v){to[++tot]=b;w[tot]=v;next[tot]=head[a];head[a]=tot;} void build(segtree *p, int l, int r) { int mid=(l+r)>>1; p->l=l,p->r=r; if(l==r){p->w=val[l];return;} build(p->lch=new segtree,l,mid); build(p->rch=new segtree,mid+1,r); p->w=p->lch->w xor p->rch->w; } int segsum(segtree *p, int l, int r) { int mid=(p->l+p->r)>>1, ans=0; if(l<=p->l and r>=p->r)return p->w; if(l<=mid)ans=ans xor segsum(p->lch,l,r); if(r>mid)ans=ans xor segsum(p->rch,l,r); return ans; } void dfs1(int pos) { int p, x; size[pos]=1; for(p=head[pos];p;p=next[p]) { x=to[p]; if(x==fa[pos])continue; fa[x]=pos; deep[x]=deep[pos]+1; tmp[x]=w[p]; dfs1(x); if(son[pos]==0 or size[x]>size[son[pos]])son[pos]=x; size[pos]+=size[x]; } } void dfs2(int pos, int tp) { int p, x; tid[pos]=++tim; top[pos]=tp; if(son[pos])dfs2(son[pos],tp); for(p=head[pos];p;p=next[p]) { x=to[p]; if(x==fa[pos] or x==son[pos])continue; dfs2(x,x); } } int sum(int a, int b) { int ta=top[a], tb=top[b], ans=0; while(ta!=tb) { if(deep[ta]<deep[tb])swap(ta,tb),swap(a,b); ans=ans xor segsum(root,tid[ta],tid[a]); a=fa[ta];ta=top[a]; } if(deep[a]>deep[b])swap(a,b); ans=ans xor segsum(root,tid[a],tid[b]); ans=ans xor segsum(root,tid[a],tid[a]); return ans; } int main() { int i, a, b, c, M; scanf("%d",&N); for(i=1;i<N;i++)scanf("%d%d%d",&a,&b,&c),adde(a,b,c),adde(b,a,c); dfs1(1); dfs2(1,1); for(i=1;i<=N;i++)val[tid[i]]=tmp[i]; build(root=new segtree,1,tim); scanf("%d",&M); for(i=1;i<=M;i++) { scanf("%d%d",&a,&b); printf("%d\n",sum(a,b)); } return 0; }
//树上前缀和 #include <cstdio> #include <algorithm> #define maxn 200010 using namespace std; int N, M, head[maxn], to[maxn], w[maxn], next[maxn], tot, s[maxn]; void adde(int a, int b, int c){to[++tot]=b;w[tot]=c;next[tot]=head[a];head[a]=tot;} void input() { int i, a, b, c; scanf("%d",&N); for(i=1;i<N;i++)scanf("%d%d%d",&a,&b,&c),adde(a,b,c),adde(b,a,c); } void dfs(int pos, int pre) { int p; for(p=head[pos];p;p=next[p]) { if(to[p]==pre)continue; s[to[p]]=s[pos] xor w[p]; dfs(to[p],pos); } } int main() { int i, a, b, m; input(); dfs(1,0); scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); printf("%d\n",s[a] xor s[b]); } return 0; }
//LCT #include <cstdio> #include <algorithm> #define maxn 500000 using namespace std; int N, M; struct node { int sum, rev, w; node *f, *ch[2]; }nd[maxn], *s[maxn]; inline int read(int x=0) { char c=getchar(); while(c<48 or c>57)c=getchar(); while(c>=48 and c<=57)x=x*10+c-48,c=getchar(); return x; } inline int getwh(node *x) {if(!x->f)return -1;if(x->f->ch[0]==x)return 0;if(x->f->ch[1]==x)return 1;return -1;} inline bool isroot(node *x){return getwh(x)==-1;} inline void join(node *x, node *y, int wh){if(x)x->f=y;if(y)y->ch[wh]=x;} inline void rever(node *x){if(x)x->rev^=1;} inline void pushdown(node *x) { if(x->rev) { swap(x->ch[0],x->ch[1]); rever(x->ch[0]),rever(x->ch[1]); x->rev=0; } } inline void pushup(node *x) { x->sum=x->w; if(x->ch[0])x->sum^=x->ch[0]->sum; if(x->ch[1])x->sum^=x->ch[1]->sum; } inline void rotate(node *x) { node *y=x->f, *z=y->f; int c=getwh(x); if(isroot(y))x->f=y->f;else join(x,z,getwh(y)); join(x->ch[!c],y,c); join(y,x,!c); pushup(y),pushup(x); } inline void splay(node *x) { node *y; int top=0; for(y=x;!isroot(y);y=y->f)s[++top]=y;s[++top]=y; for(;top;top--)pushdown(s[top]); while(!isroot(x)) { y=x->f; if(isroot(y)){rotate(x);return;} if(getwh(x)^getwh(y))rotate(x);else rotate(y); rotate(x); } } inline void access(node *x) { node *t=0; while(x) { splay(x); x->ch[1]=t; pushup(x); t=x;x=x->f; } } inline void makeroot(node *x){access(x);splay(x);rever(x);} inline void link(node *x, node *y){makeroot(x);x->f=y;} void init() { int a, b, c, i; N=read(); for(i=1;i<N;i++) { a=read(),b=read(),c=read(); nd[N+i].w=nd[N+i].sum=c; link(nd+N+i,nd+a);link(nd+N+i,nd+b); access(nd+a),splay(nd+a); } } inline int work(int a, int b) { makeroot(nd+a),access(nd+b);splay(nd+b); return nd[b].sum; } int main() { int a, b; init(); for(M=read();M;M--)a=read(),b=read(),printf("%d\n",work(a,b)); return 0; }
相关文章推荐
- 【LCA】洛谷2420[让我们异或吧]题解
- 你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的n种颜色的颜料,你现在可以去商店购买一些颜料,但是商店不能保证能供应所有颜色的颜料,所以你需要自己混合一些颜料。混合两种不一样的颜色A和颜色B颜料可以产生(A XOR B)这种颜色的颜料(新产生的颜料也可以用作继续混合产生新的颜色,XOR表示异或操作)。本着勤俭节约的
- [luoguP2420] 让我们异或吧(dfs + 异或的性质)
- 洛谷——P2420 让我们异或吧
- P2420 让我们异或吧(倍增)
- luogu P2420 让我们异或吧 题解
- 洛谷 2420 让我们异或吧
- luogu 2420
- 洛谷P2420 让我们异或吧 树上差分 dfs
- 洛谷 P2420 让我们异或吧 树形dp
- 洛谷 2420 让我们异或吧
- AC日记——让我们异或吧 洛谷 P2420
- 我们一起来编程!
- 我是如何折腾.NET Resx资源文件的 当计算机中的资源已经足够多时,我们也要学会尽可能的借用
- 我们在网站推广运营的时候应该注意什么?
- 论那些年我们讨论过的Bank系统!
- 刘轩-不要让我们的身体骗了我们
- 我们的纪念日
- 为什么我们不要.NET程序员
- 原来我们不懂百度seo排名和百度竞价