日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[bzoj 4811] 由乃的OJ(贪心 + 树链剖分)

發布時間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [bzoj 4811] 由乃的OJ(贪心 + 树链剖分) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前置技能:[Noi2014]起床困難綜合癥。

不難看出,這道題其實就是上一道題的加強版
在上一道題中,因為位運算時位與位之間互不干擾
所以從高位到低位枚舉初始值二進制上的每一位為0和為1時,經過n次計算后這一位的結果,貪心選取
在這題中,我們也可以用同樣的思路求取答案
因為有樹上路徑查詢,考慮樹鏈剖分,用線段樹維護每一位初始為0和1時,經過一個區間的計算變為多少
因為&、|、^ 運算都符合結合律,所以這樣做是可行的
問題是,&、|、^ 運算并不都滿足交換律,即每個區間從左到右計算和從右到左計算得到的結果是不同的
而在樹上從x走到y的途中,并不保證一定按dfn序從小到大的順序走
所以我們還要分別維護每個區間從左到右計算和從右到左計算的結果
另外,給每一位都開一顆線段樹顯然是不現實的,
考慮到 k<=64,我們使用狀壓,把所有位都壓到一起,存到一顆線段樹中(注意要開unsigned long long)

#include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int N=100010; ull read(){ull x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f; } struct Edge{int u,v,nxt; }edge[N<<1]; int head[N],cnt; void addedge(int u,int v){edge[++cnt]=(Edge){u,v,head[u]};head[u]=cnt;edge[++cnt]=(Edge){v,u,head[v]};head[v]=cnt; } int n,m,k; int dep[N],son[N],sz[N],top[N],fa[N],tid[N],rnk[N],ind; void dfs1(int u,int f){fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;for(int i=head[u];~i;i=edge[i].nxt) if(edge[i].v!=f){dfs1(edge[i].v,u);if(sz[edge[i].v]>sz[son[u]]) son[u]=edge[i].v;sz[u]+=sz[edge[i].v];} } void dfs2(int u,int tp){top[u]=tp;tid[u]=++ind;rnk[ind]=u;if(sz[u]>1) dfs2(son[u],tp);for(int i=head[u];~i;i=edge[i].nxt) if(edge[i].v!=son[u]&&edge[i].v!=fa[u])dfs2(edge[i].v,edge[i].v); } ull tran[N<<3][2][2]; //tran[o][0:帶進0計算 ? 1:帶進1計算][0:從左往右算 ? 1:從右往左算] inline ull transf(ull a,ull b,int opt){if(opt==1){return a&b;}else if(opt==2){return a|b;}else return a^b; } int op; inline ull transf(ull a,ull b){if(op==1){return a&b;}else if(op==2){return a|b;}else return a^b; } inline void pushup(int o){int ls=o<<1,rs=o<<1|1;tran[o][1][0]=(tran[ls][1][0]&tran[rs][1][0])|(~tran[ls][1][0]&tran[rs][0][0]);tran[o][1][1]=(tran[rs][1][1]&tran[ls][1][1])|(~tran[rs][1][1]&tran[ls][0][1]);tran[o][0][0]=(tran[ls][0][0]&tran[rs][1][0])|(~tran[ls][0][0]&tran[rs][0][0]);tran[o][0][1]=(tran[rs][0][1]&tran[ls][1][1])|(~tran[rs][0][1]&tran[ls][0][1]); } void update(int o,int l,int r,int x,ull k){if(l==r){tran[o][0][0]=tran[o][0][1]=transf(0ull,k);tran[o][1][0]=tran[o][1][1]=transf(~0ull,k);}else{int mid=l+r>>1;if(x<=mid) update(o<<1,l,mid,x,k);else update(o<<1|1,mid+1,r,x,k);pushup(o); } } ull t1[2],t0[2]; int t; void query(int o,int l,int r,int a,int b){if(a<=l&&b>=r){ if(!t){ull tt=t1[t];t1[t]=(tran[o][1][t]&t1[t])|(~tran[o][1][t]&t0[t]);t0[t]=(tran[o][0][t]&tt)|(~tran[o][0][t]&t0[t]);}else{t1[t]=(t1[t]&tran[o][1][t])|(~t1[t]&tran[o][0][t]);t0[t]=(t0[t]&tran[o][1][t])|(~t0[t]&tran[o][0][t]); }}else{int mid=l+r>>1;if(b>mid) query(o<<1|1,mid+1,r,a,b);if(a<=mid) query(o<<1,l,mid,a,b); } } ull val[N]; int opt[N]; void build(int o,int l,int r){if(l==r){ tran[o][0][0]=tran[o][0][1]=transf(0ull,val[rnk[l]],opt[rnk[l]]);tran[o][1][0]=tran[o][1][1]=transf(~0ull,val[rnk[l]],opt[rnk[l]]);}else{int mid=l+r>>1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);pushup(o);} } ull z; inline ull ask(int x,int y){t0[0]=t0[1]=0;t1[0]=t1[1]=~0ull;while(top[x]!=top[y]){if(dep[top[x]]>dep[top[y]]){t=1;query(1,1,n,tid[top[x]],tid[x]);x=fa[top[x]];}else{t=0;query(1,1,n,tid[top[y]],tid[y]);y=fa[top[y]];}}if(dep[x]>dep[y]){t=1;query(1,1,n,tid[y],tid[x]); }else{t=0;query(1,1,n,tid[x],tid[y]);}ull T0=(t0[1]&t1[0])|(~t0[1]&t0[0]);ull T1=(t1[1]&t1[0])|(~t1[1]&t0[0]);ull v=0,ans=0;for(int i=k;~i;i--){ull v1=v|(1ull<<i);if(v1<=z){if(T0&(1ull<<i)||!(T1&(1ull<<i)))ans|=T0&(1ull<<i);else{ans|=T1&(1ull<<i);v|=(1ull<<i);}}else{ans|=T0&(1ull<<i);}}return ans; } int main(){memset(head,cnt=-1,sizeof(head));n=read();m=read();k=read();k--;for(int i=1;i<=n;i++)opt[i]=read(),val[i]=read();for(int i=1;i<n;i++)addedge(read(),read());dfs1(1,1);dfs2(1,1);build(1,1,n);while(m--){int q=read(),x=read( ),y=read( );z=read( );if(q==1) printf("%llu\n",ask(x,y));else{op=y;update(1,1,n,tid[x],z);}}return 0; }

總結

以上是生活随笔為你收集整理的[bzoj 4811] 由乃的OJ(贪心 + 树链剖分)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。