【BZOJ2908】又是nand 树链剖分+线段树
生活随笔
收集整理的這篇文章主要介紹了
【BZOJ2908】又是nand 树链剖分+线段树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【BZOJ2908】又是nand
escription
首先知道A nand B=not(A and B) (運算操作限制了數位位數為K)比如2 nand 3,K=3,則2 nand 3=not (2 and 3)=not 2=5。 給出一棵樹,樹上每個點都有點權,定義樹上從a到b的費用為0與路徑上的點的權值順次nand的結果,例如:從2號點到5號點順次經過2->3->5,權值分別為5、7、2,K=3,那么最終結果為0 nand 5 nand 7 nand 2=7 nand 7 nand 2=0 nand 2=7,現在這棵樹需要支持以下操作。 ① ? ?Replace a b:將點a(1≤a≤N)的權值改為b。 ② ? ?Query a b:輸出點a到點b的費用。 請眾神給出一個程序支持這些操作。Input
第一行N,M,K,樹的節點數量、總操作個數和運算位數。 接下來一行N個數字,依次表示節點i的權值。 接下來N-1行,每行兩個數字a,b(1≤a,b≤N)表示a,b間有一條樹邊。 接下來M行,每行一個操作,為以上2類操作之一。 N、M≤100000,K≤32Output
對于操作②每個輸出一行,如題目所述。
Sample Input
3 3 32 7 3
1 2
2 3
Query 2 3
Replace 1 3
Query 1 1
Sample Output
47
題解:網上都說要拆位,那么我也拆位吧~(不拆位好像也能做?)
首先,nand滿足交換律但不滿足結合律。
我們先樹剖,然后對于每一位,都用線段樹維護tl[d][x],代表如果該位是d,從左邊來經過這個區間后會變成的數,tr[d][x]代表如果該位是d,從右往左經過這個區間后會變成的數。然后就是區間合并的事了~
對于詢問a,b,我們先求出從a向上走到lca的變化,再求出從lca向下走到b的變化即可。
?
#include <cstdio> #include <cstring> #include <iostream> #define lson x<<1 #define rson x<<1|1 using namespace std; int n,m,k,cnt; char str[10]; const int maxn=100010; int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn],dep[maxn],siz[maxn],top[maxn],son[maxn],p[maxn],q[maxn],st[maxn]; unsigned v[maxn]; struct seg {bool tl[2][maxn<<2],tr[2][maxn<<2];void pushup(int x){tl[0][x]=tl[tl[0][lson]][rson],tl[1][x]=tl[tl[1][lson]][rson];tr[0][x]=tr[tr[0][rson]][lson],tr[1][x]=tr[tr[1][rson]][lson];}void build(int l,int r,int x,int a){if(l==r){tl[0][x]=tr[0][x]=1,tl[1][x]=tr[1][x]=!((v[q[l]]>>a)&1);return ;}int mid=l+r>>1;build(l,mid,lson,a),build(mid+1,r,rson,a);pushup(x);}void updata(int l,int r,int x,int a,bool b){if(l==r){tl[0][x]=tr[0][x]=1,tl[1][x]=tr[1][x]=!b;return ;}int mid=l+r>>1;if(a<=mid) updata(l,mid,lson,a,b);else updata(mid+1,r,rson,a,b);pushup(x);}bool ql(int l,int r,int x,int a,int b,bool c){if(a<=l&&r<=b) return tl[c][x];int mid=l+r>>1;if(b<=mid) return ql(l,mid,lson,a,b,c);if(a>mid) return ql(mid+1,r,rson,a,b,c);return ql(mid+1,r,rson,a,b,ql(l,mid,lson,a,b,c));}bool qr(int l,int r,int x,int a,int b,bool c){if(a<=l&&r<=b) return tr[c][x];int mid=l+r>>1;if(b<=mid) return qr(l,mid,lson,a,b,c);if(a>mid) return qr(mid+1,r,rson,a,b,c);return qr(l,mid,lson,a,b,qr(mid+1,r,rson,a,b,c));} }s[33]; inline int rd() {int ret=0; char gc=getchar();while(gc<'0'||gc>'9') gc=getchar();while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();return ret; } void dfs1(int x) {siz[x]=1;for(int i=head[x];i!=-1;i=next[i]){if(to[i]!=fa[x]){fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];if(siz[to[i]]>siz[son[x]]) son[x]=to[i];}} } void dfs2(int x,int tp) {top[x]=tp,p[x]=++p[0],q[p[0]]=x;if(son[x]) dfs2(son[x],tp);for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]); } void add(int a,int b) {to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } void ask(int x,int y) {unsigned int ret=0;int i;st[0]=0;while(top[x]!=top[y]){if(dep[top[x]]>=dep[top[y]]){for(i=0;i<k;i++) ret=ret-(ret&(1<<i))+(s[i].qr(1,n,1,p[top[x]],p[x],(ret>>i)&1)<<i);x=fa[top[x]];}else st[++st[0]]=y,y=fa[top[y]];}if(dep[x]<dep[y]) for(i=0;i<k;i++) ret=ret-(ret&(1<<i))+(s[i].ql(1,n,1,p[x],p[y],(ret>>i)&1)<<i);else for(i=0;i<k;i++) ret=ret-(ret&(1<<i))+(s[i].qr(1,n,1,p[y],p[x],(ret>>i)&1)<<i);for(y=st[0];y;y--) for(i=0;i<k;i++) ret=ret-(ret&(1<<i))+(s[i].ql(1,n,1,p[top[st[y]]],p[st[y]],(ret>>i)&1)<<i);printf("%u\n",ret); } int main() {n=rd(),m=rd(),k=rd();int i,j,a,b;for(i=1;i<=n;i++) scanf("%u",&v[i]);memset(head,-1,sizeof(head));for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);dep[1]=1,dfs1(1),dfs2(1,1);for(i=0;i<k;i++) s[i].build(1,n,1,i);for(i=1;i<=m;i++){scanf("%s",str);if(str[0]=='Q') a=rd(),b=rd(),ask(a,b);else{a=rd(),scanf("%u",&v[a]);for(j=0;j<k;j++) s[j].updata(1,n,1,p[a],(v[a]>>j)&1);}}return 0; }//3 3 3 2 7 3 1 2 2 3 Query 2 3 Replace 1 3 Query 1 1?
轉載于:https://www.cnblogs.com/CQzhangyu/p/7327672.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【BZOJ2908】又是nand 树链剖分+线段树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机械零点、MAM 文件 、 EMT标
- 下一篇: struct和typedef struc