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); } } }