NC205397. 异或Tree
描述
前置定义:(牛逼值)
给定一个长度为n的数组:,该数组的牛逼值为:。其中表示异或运算,与传统异或运算定义一致。
例如长度为3的数组:,那么他的牛逼值为:
=10。
题面:
lt是一个三维生物,他掌管着二维世界的运行规律,某一天他发现一颗有个节点的无根树,该树只有点权,没有边权,现在他要进行次操作,每次进行以下两种操作之一:
输入描述
单组输入。
第一行输入n,m,代表树的节点个数,以及进行的操作次数,保证。
第二行输入n个正整数,代表每个节点的点权,保证输入值。
接下来n-1行,每行两个正整数u,v,表示节点与节点之间有一条双向边,保证输入规模为一颗树,且1<=u,v<=n且u!=v。
接下来m行,每行三个数字id,u,v,保证1<=id<=2。
若id=1,则表示是第一种操作,此时,将节点u的点权修改为v。
若id=2,则表示是第二种操作1<=u,v<=n,此时,你需要输出该次询问结果。
输出描述
对于每个第二种操作输出一行,表示该次询问的结果。保证64位整数可以存下结果
示例1
输入:
3 3 1 2 4 1 2 1 3 2 2 3 1 1 8 2 2 3
输出:
22 50
说明:
示例2
输入:
10 10 4 3 1 1 6 1 6 2 8 10 1 2 2 3 2 4 4 5 5 6 3 7 3 8 2 9 9 10 1 4 1 2 10 5 1 2 9 1 9 10 2 5 4 2 1 1 2 1 9 1 8 8 2 2 6 2 6 2
输出:
83 14 4 46 74 74
说明:
一组友好的帮助debug的大样例C++14(g++5.4) 解法, 执行用时: 722ms, 内存消耗: 42360K, 提交时间: 2020-05-25 23:28:02
#include <bits/stdc++.h> #define mp make_pair #define pb push_back #define sz(x) (int)x.size() #define all(x) begin(x), end(x) #define fi first #define se second #define debug(x) cerr << #x << " " << x << '\n' using namespace std; using ll = long long; using pii = pair<int,int>; using pli = pair<ll,int>; const int INF = 0x3f3f3f3f, N = 5e4 + 5; const ll LINF = 1e18 + 5; constexpr int mod = 1e9 + 7; int n, m, a[N], b[N]; vector<int> G[N]; int sz[N], top[N], son[N], dep[N], fa[N], dfn[N], idfn[N], tot; int cnt[32], cnt1[32], cnt2[32]; namespace SegTree { #define ls (p<<1) #define rs (p<<1|1) struct seg { int l, r; int sum[32], tag[32]; }t[N<<2]; void pushup(int p) { for(int i=0; i<30; i++) t[p].sum[i] = t[ls].sum[i] + t[rs].sum[i]; } void setval(int p, int i) { t[p].sum[i] = t[p].r - t[p].l + 1 - t[p].sum[i]; t[p].tag[i] ^= 1; } void pushdown(int p) { for(int i=0; i<30; i++) if(t[p].tag[i]) { setval(ls, i); setval(rs, i); t[p].tag[i] = 0; } } void build(int p, int l, int r) { t[p].l = l, t[p].r = r; if(l==r) { for(int i=0; i<30; i++) t[p].sum[i] = (a[idfn[l]]>>i)&1; return; } int mid = (l+r)>>1; build(ls, l, mid); build(rs, mid+1, r); pushup(p); } void upd(int p, int x, int y, int v) { int l = t[p].l, r = t[p].r; if(l>=x && r<=y) { for(int i=0; i<30; i++) if((v>>i)&1) setval(p, i); return; } pushdown(p); int mid = (l+r)>>1; if(x<=mid) upd(ls, x, y, v); if(y>mid) upd(rs, x, y, v); pushup(p); } void ask(int p, int x, int y) { int l = t[p].l, r = t[p].r; if(l>=x && r<=y) { for(int i=0; i<30; i++) cnt[i] += t[p].sum[i]; return; } pushdown(p); int mid = (l+r)>>1; if(x<=mid) ask(ls, x, y); if(y>mid) ask(rs, x, y); } #undef ls #undef rs } using namespace SegTree; void dfs1(int u, int f) { dep[u] = dep[f] + 1; fa[u] = f; sz[u] = 1; a[u] ^= a[f]; for(int v : G[u]) { if(v!=f) { dfs1(v, u); sz[u] += sz[v]; if(sz[v]>sz[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { top[u] = t; dfn[u] = ++tot; idfn[tot] = u; if(!son[u]) return; dfs2(son[u], t); for(int v : G[u]) if(v!=son[u]&&v!=fa[u]) dfs2(v, v); } int LCA(int x, int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } void askt(int x, int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ask(1, dfn[top[x]], dfn[x]); x = fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); ask(1, dfn[x], dfn[y]); } int main() { scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) scanf("%d", a+i), b[i] = a[i]; for(int i=1; i<n; i++) { int u, v; scanf("%d%d", &u, &v); G[u].pb(v); G[v].pb(u); } dfs1(1, 0); dfs2(1, 1); build(1, 1, n); for(int i=1; i<=m; i++) { int op, u, v; scanf("%d%d%d", &op, &u, &v); if(op==1) { upd(1, dfn[u], dfn[u]+sz[u]-1, b[u]^v); b[u] = v; } else { int w = LCA(u, v); for(int i=0; i<30; i++) cnt[i] = 0; askt(u, w); memcpy(cnt1, cnt, sizeof(cnt)); for(int i=0; i<30; i++) cnt[i] = 0; askt(v, w); memcpy(cnt2, cnt, sizeof(cnt)); ll ans = 0; for(int i=0; i<30; i++) { int x = cnt1[i], y = cnt2[i]; int xx = dep[u] - dep[w] + 1 - x, yy = dep[v] - dep[w] + 1 - y; ll cur = 1ll*x*xx+1ll*y*yy; if((b[w]>>i)&1) cur += 1ll*x*y + 1ll*xx*yy; else cur += 1ll*x*yy + 1ll*xx*y; ans += cur*(1<<i); } printf("%lld\n", ans); } } return 0; }
C++11(clang++ 3.9) 解法, 执行用时: 455ms, 内存消耗: 106724K, 提交时间: 2020-05-26 12:23:40
#include<bits/stdc++.h> #define L(x) (x<<1) #define R(x) (x<<1|1) #define M(x) ((T[x].l+T[x].r)>>1) using namespace std; typedef long long ll; const int N=5e4+11,M=31; typedef long long ll; struct Tree{ int l,r,len; int sum[M],lj[M],rj[M],cnt[M]; Tree(){ l=r=len=0; for(int i=0;i<M;i++) sum[i]=lj[i]=rj[i]=cnt[i]=0; } }T[N<<2]; int a[N],b[N]; Tree merge(Tree &ll,Tree &rr){ Tree ans; ans.l=ll.l;ans.r=rr.r; for(int i=0;i<M;i++){ ans.sum[i]=ll.sum[i]+rr.sum[i]; ans.sum[i]+=ll.rj[i]*(rr.len-rr.lj[i]); ans.sum[i]+=rr.lj[i]*(ll.len-ll.rj[i]); if(ll.cnt[i]&1) ans.lj[i]=ll.lj[i]+(rr.len-rr.lj[i]); else ans.lj[i]=ll.lj[i]+rr.lj[i]; if(rr.cnt[i]&1) ans.rj[i]=rr.rj[i]+(ll.len-ll.rj[i]); else ans.rj[i]=rr.rj[i]+ll.rj[i]; ans.cnt[i]=ll.cnt[i]+rr.cnt[i]; } ans.len=ll.len+rr.len; return ans; } void build(int x,int l,int r){ T[x].l=l;T[x].r=r; if(l==r){ T[x].len=1; for(int i=0;i<M;i++){ T[x].sum[i]=T[x].lj[i]=T[x].rj[i]=T[x].cnt[i]=((b[l]>>i)&1); } return ; } build(L(x),l,M(x)); build(R(x),M(x)+1,r); T[x]=merge(T[L(x)],T[R(x)]); return ; } void updata(int x,int pos,int val){ if(T[x].l==pos&&T[x].r==pos){ for(int i=0;i<M;i++){ T[x].sum[i]=T[x].lj[i]=T[x].rj[i]=T[x].cnt[i]=((val>>i)&1); } return ; } if(pos<=M(x)) updata(L(x),pos,val); else updata(R(x),pos,val); T[x]=merge(T[L(x)],T[R(x)]); return ; } Tree query(int x,int l,int r){ if(l<=T[x].l&&r>=T[x].r) return T[x]; if(r<=M(x)) return query(L(x),l,r); else if(l>M(x)) return query(R(x),l,r); else{ Tree ll=query(L(x),l,r),rr=query(R(x),l,r); return merge(ll,rr); } } //上面为线段树 struct Side{ int v,ne; }S[N<<1]; char op[18]; int sn,head[N],tn,tid[N],size[N],dep[N]; int top[N],fa[N],son[N]; void initS(int n){ sn=tn=0; for(int i=0;i<=n;i++){ fa[i]=son[i]=0; size[i]=1; dep[i]=1; head[i]=-1; } } void addS(int u,int v){ S[sn].v=v; S[sn].ne=head[u]; head[u]=sn++; } void dfs1(int u){ for(int i=head[u];~i;i=S[i].ne){ int v=S[i].v; if(v==fa[u]) continue; fa[v]=u; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[v]>=size[son[u]]) son[u]=v; } } void dfs2(int u,int tf){ tid[u]=++tn; b[tn]=a[u]; top[u]=tf; if(!son[u]) return ; dfs2(son[u],tf); for(int i=head[u];i!=-1;i=S[i].ne){ int v=S[i].v; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } Tree querypath(int x,int y){ int flag=1; Tree ans1,ans2,temp; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]){ flag^=1; swap(x,y); } temp=query(1,tid[top[x]],tid[x]); if(flag){ for(int i=0;i<M;i++) swap(temp.lj[i],temp.rj[i]); ans1=merge(ans1,temp); }else ans2=merge(temp,ans2); x=fa[top[x]]; } flag^=1; if(dep[x]>dep[y]){ swap(x,y); flag^=1; } temp=query(1,tid[x],tid[y]); if(flag){ for(int i=0;i<M;i++) swap(temp.lj[i],temp.rj[i]); ans1=merge(ans1,temp); }else ans2=merge(temp,ans2); ans1=merge(ans1,ans2); return ans1; } int main(){ int t,n,m,op,u,v; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); initS(n); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addS(u,v); addS(v,u); } dfs1(1); dfs2(1,1); build(1,1,n); while(m--){ scanf("%d%d%d",&op,&u,&v); if(op==1) updata(1,tid[u],v); else{ Tree ans=querypath(u,v); ll res=0; for(int i=M-1;i>=0;i--) res=((res<<1ll)+ans.sum[i]); printf("%lld\n",res); } } return 0; } //3 3 //1 2 3 //1 2 //1 3 //2 2 3 //1 1 2 //2 1 1