BZOJ_3589_動態樹_容斥原理+樹鏈剖分
阿新 • • 發佈:2018-03-11
query using mod mask tin 容斥原理 urn con pos
BZOJ_3589_動態樹_容斥原理+樹鏈剖分
題意:
維護一棵樹,支持1.子樹內點權加上一個數 2.給出k條鏈,求路徑上的點權和(重復的計算一次) (k<=5)
分析:
可以用樹剖+線段樹解決第一個操作
然後我們發現k非常小,可以二進制枚舉
那就容斥一下轉化成求幾條鏈的交
鏈交求法:鏈頂是兩條鏈頂深度大的那個,鏈底是兩個鏈底的lca
如果鏈底深度小於鏈頂,就說明兩條鏈沒有交集
代碼:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 200050 #define LL long long #define ls p<<1 #define rs p<<1|1 int head[N],to[N<<1],nxt[N<<1],cnt,n,q,xx[10],yy[10]; int fa[N],dep[N],top[N],siz[N],son[N],idx[N],tot,k; int _count[100],strtop[10],strbot[10]; LL mod=2147483648ll; LL t[N<<2],add[N<<2]; inline void adde(int u,int v){ to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt; } void dfs1(int x,int y){ int i; fa[x]=y;dep[x]=y+1; siz[x]=1; for(i=head[x];i;i=nxt[i]){ if(to[i]!=y){ dfs1(to[i],x); siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[son[x]])son[x]=to[i]; } } } void dfs2(int x,int t){ top[x]=t;idx[x]=++tot; int i; if(son[x]) dfs2(son[x],t); for(i=head[x];i;i=nxt[i]){ if(to[i]!=fa[x]&&to[i]!=son[x]){ dfs2(to[i],to[i]); } } } void pud(int l,int r,int p){ if(add[p]==0)return ; add[ls]+=add[p]; add[ls]%=mod; add[rs]+=add[p]; add[rs]%=mod; int mid=l+r>>1; t[ls]+=add[p]*(mid-l+1); t[ls]%=mod; t[rs]+=add[p]*(r-mid); t[rs]%=mod; add[p]=0; } void update(int l,int r,int x,int y,int c,int p){ if(x<=l&&y>=r){ t[p]+=1ll*c*(r-l+1); add[p]+=c; t[p]%=mod; add[p]%=mod; return ; } pud(l,r,p); int mid=l+r>>1; if(x<=mid)update(l,mid,x,y,c,ls); if(y>mid)update(mid+1,r,x,y,c,rs); t[p]=t[ls]+t[rs]; t[p]%=mod; } LL query(int l,int r,int x,int y,int p){ if(x<=l&&y>=r) return t[p]; int mid=l+r>>1; LL re=0; pud(l,r,p); t[p]=t[ls]+t[rs]; t[p]%=mod; if(x<=mid)re=(re+query(l,mid,x,y,ls))%mod; if(y>mid)re=(re+query(mid+1,r,x,y,rs))%mod; return re%mod; } LL ask(int x,int y){ LL re=0; while(top[x]!=top[y]){ if(dep[top[x]]>dep[top[y]])swap(x,y); re+=query(1,n,idx[top[y]],idx[y],1); re%=mod; y=fa[top[y]]; } if(dep[x]<dep[y])swap(x,y); return (re+query(1,n,idx[y],idx[x],1))%mod; } void fix(int x,int c){ update(1,n,idx[x],idx[x]+siz[x]-1,c,1); } int lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]>dep[top[y]])swap(x,y); y=fa[top[y]]; } return dep[x]<dep[y]?x:y; } void solve(){ int mask=(1<<k)-1; int i,flg,j; LL ans=0; for(i=1;i<=k;i++){ if(dep[xx[i]]>dep[yy[i]])swap(xx[i],yy[i]); strtop[i]=xx[i];strbot[i]=yy[i]; } for(i=1;i<=mask;i++){ if((_count[i]&1))flg=1; else flg=-1; int no_jiao=0; int top_a=0,bot_a=0; for(j=1;j<=k;j++){ if(i&(1<<j-1)){ if(!top_a){ top_a=strtop[j]; bot_a=strbot[j]; } else { bot_a=lca(bot_a,strbot[j]); if(dep[top_a]<dep[strtop[j]]){ top_a=strtop[j]; } if(dep[top_a]>dep[bot_a])no_jiao=1; } } } if(no_jiao)continue; ans+=flg*ask(top_a,bot_a); ans=(ans+mod)%mod; } printf("%lld\n",ans); } int main(){ scanf("%d",&n); int i,x,y,opt,j; for(i=1;i<n;i++){ scanf("%d%d",&x,&y); adde(x,y);adde(y,x); } dfs1(1,0); dfs2(1,1); for(i=1;i<=32;i++){ _count[i]=_count[i>>1]+(i&1); } scanf("%d",&q); while(q--){ scanf("%d",&opt); if(opt){ scanf("%d",&k); for(j=1;j<=k;j++){ scanf("%d%d",&xx[j],&yy[j]); } solve(); }else{ scanf("%d%d",&x,&y); fix(x,y); } } }
BZOJ_3589_動態樹_容斥原理+樹鏈剖分