bzoj 2152 聪聪可可
题目大意:
求树上边权和为3的倍数的路径的条数
思路:
点分治练习题
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17 #define inf 1000000000 18 #define MAXN 100100 19 #define MOD 998244353 20 using namespace std; 21 inline int read() 22 { 23 int x=0,f=1;char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 25 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt,res[3]; 29 int q[MAXN],ans,sz[MAXN],mx[MAXN],rt,Mx,Sum,vis[MAXN],g[MAXN],len; 30 int gcd(int a,int b) {return !b?a:gcd(b,a%b);} 31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 32 void getrt(int x,int pa) 33 { 34 sz[x]=1,mx[x]=0;ren if(to[i]!=pa&&!vis[to[i]]) {getrt(to[i],x);sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);} 35 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 36 } 37 void getdis(int x,int pa,int dep) {res[dep%3]++;ren if(to[i]!=pa&&!vis[to[i]]) getdis(to[i],x,dep+val[i]);} 38 int calc(int x,int dep) 39 { 40 Fill(res,0);getdis(x,0,dep);return res[0]*res[0]+res[1]*res[2]*2; 41 } 42 void div(int x) 43 { 44 vis[x]=1;ans+=calc(x,0); 45 ren if(!vis[to[i]]) {Sum=sz[to[i]],Mx=inf;ans-=calc(to[i],val[i]);getrt(to[i],0);div(rt);} 46 } 47 int main() 48 { 49 n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 50 Sum=n,Mx=inf;getrt(1,0);div(1);a=n*n,b=gcd(a,ans);printf("%d/%d",ans/b,a/b); 51 }
但是树形dp明显更加优秀
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define mns(a,b) ((a-b)%3+3)%3 16 #define ll long long 17 #define ull unsigned long long 18 #define inf 1000000000 19 #define MAXN 20010 20 #define MOD 998244353 21 using namespace std; 22 inline int read() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 26 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt,dp[MAXN][3],ans; 30 int gcd(int a,int b) {return !b?a:gcd(b,a%b);} 31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 32 void dfs(int x,int pa) 33 { 34 dp[x][0]=1;ren if(to[i]!=pa) 35 { 36 dfs(to[i],x); 37 ans+=dp[to[i]][mns(0,val[i])]*dp[x][0]+dp[x][1]*dp[to[i]][mns(2,val[i])]+dp[x][2]*dp[to[i]][mns(1,val[i])]; 38 rep(j,0,2) dp[x][(j+val[i])%3]+=dp[to[i]][j]; 39 } 40 } 41 int main() 42 { 43 n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 44 dfs(1,0);(ans<<=1)+=n,a=n*n,b=gcd(a,ans);printf("%d/%d",ans/b,a/b); 45 }
luogu 3806 【模板】 点分治1
题目大意:
树上Q次询问 每次询问路径长度为k的路径是否存在
思路:
为什么那么多$n^2$合并的代码啊喂
由于询问数较小 跑Q次点分治即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17 #define inf 1000000000 18 #define MAXN 100100 19 #define MOD 998244353 20 using namespace std; 21 inline int read() 22 { 23 int x=0,f=1;char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 25 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt; 29 int q[MAXN],ans[MAXN],sz[MAXN],mx[MAXN],rt,Mx,Sum,vis[MAXN],g[MAXN],len; 30 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 31 void getrt(int x,int pa) 32 { 33 sz[x]=1,mx[x]=0;ren if(to[i]!=pa&&!vis[to[i]]) {getrt(to[i],x);sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);} 34 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 35 } 36 void getdis(int x,int pa,int dep) {g[++len]=dep;ren if(to[i]!=pa&&!vis[to[i]]) getdis(to[i],x,dep+val[i]);} 37 void calc(int x,int dep,int val) 38 { 39 int res=0,l,r;len=0;getdis(x,0,dep);sort(g+1,g+len+1);l=1,r=len; 40 rep(i,1,m) 41 { 42 while(l<=r) if(g[l]+g[r]>q[i]) r--;else res+=(g[l]+g[r]==q[i]),l++; 43 ans[i]+=res*val,res=0,l=1,r=len; 44 } 45 } 46 void div(int x) 47 { 48 vis[x]=1;calc(x,0,1); 49 ren if(!vis[to[i]]) {Sum=sz[to[i]],Mx=inf;calc(to[i],val[i],-1);getrt(to[i],0);div(rt);} 50 } 51 int main() 52 { 53 n=read(),m=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 54 rep(i,1,m) q[i]=read();Sum=n,Mx=inf;getrt(1,0);div(1);rep(i,1,m) puts(ans[i]?"AYE":"NAY"); 55 }
bzoj 3672 购票
题目大意:
每个点$x$可以购买一个车票到距离不超过$lim_x$的祖先,车票价格为$p_x*(dis_{x,ancestor})+q_x$
求每个点到树的根的最小代价
思路:
首先想到了线段树分治的$log^3n$的优秀做法 然后学了一波点分治做法
很明显可以想到斜率优化 考虑如何处理距离限制
在点分治的过程中,把分治重心子树内的所有按照$dis_i-lim_i$排序,这样就可以依次由下至上加入最高点$x$-$root$的路径上的点
这样可以保证所有时刻的凸包都是满足要求的
每次分治的时候先处理树中不算分治重心儿子的部分 然后处理分治重心的儿子即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren(x) for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17 #define inf 1LL<<60 18 #define MAXN 200100 19 #define MOD 998244353 20 using namespace std; 21 inline ll read() 22 { 23 ll x=0,f=1;char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 25 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt; 29 int fa[MAXN],Sum,mx[MAXN],rt,g[MAXN],len,sz[MAXN],vis[MAXN],q[MAXN],hd,tl; 30 ll p[MAXN],Mx,b[MAXN],l[MAXN],dis[MAXN],dp[MAXN]; 31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 32 void dfs(int x) {ren(x) dis[to[i]]=dis[x]+val[i],dfs(to[i]);} 33 bool cmp(int a,int b) {return dis[a]-l[a]>dis[b]-l[b];} 34 void getrt(int x) 35 { 36 sz[x]=1,mx[x]=0;ren(x) if(!vis[to[i]]) getrt(to[i]),mx[x]=max(mx[x],sz[to[i]]),sz[x]+=sz[to[i]]; 37 mx[x]=max(mx[x],Sum-mx[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 38 } 39 void Get(int x) {g[++len]=x;ren(x) if(!vis[to[i]]) Get(to[i]);} 40 ll Y(int i,int j) {return dp[i]-dp[j];}ll X(int i,int j) {return dis[i]-dis[j];} 41 void ins(int x) {while(tl>hd&&(long double)Y(q[tl],x)*X(q[tl-1],q[tl])>=(long double)Y(q[tl-1],q[tl])*X(q[tl],x)) tl--;q[++tl]=x;} 42 int cheque(int x,int y){return Y(q[x],q[x+1])<=(long double)X(q[x],q[x+1])*p[y];} 43 void solve(int x,int sum) 44 { 45 if(sum==1) return ;Sum=sum,Mx=inf;getrt(x);int tmp=rt,pos=rt;ren(rt) vis[to[i]]=1,sum-=sz[to[i]]; 46 solve(x,sum);len=0,hd=1,tl=0;ren(pos) Get(to[i]);sort(g+1,g+len+1,cmp); 47 rep(i,1,len) 48 { 49 while(tmp!=fa[x]&&dis[g[i]]-l[g[i]]<=dis[tmp]) ins(tmp),tmp=fa[tmp]; 50 if(tl) 51 { 52 int l=1,r=tl-1,res=tl,mid;for(;mid=l+r>>1,l<=r;) if(cheque(mid,g[i])) r=mid-1,res=mid;else l=mid+1; 53 if(q[res]) dp[g[i]]=min(dp[q[res]]+p[g[i]]*(dis[g[i]]-dis[q[res]])+b[g[i]],dp[g[i]]); 54 } 55 } 56 ren(pos) solve(to[i],sz[to[i]]); 57 } 58 int main() 59 { 60 int t;n=read(),t=read();rep(i,2,n) fa[i]=read(),add(fa[i],i,read()),p[i]=read(),b[i]=read(),l[i]=read(),dp[i]=inf; 61 dfs(1);solve(1,n);rep(i,2,n) printf("%lld ",dp[i]); 62 }
bzoj 4012 开店
题目大意:
一棵树,每个点有一个权值,有边权,Q次询问
每次询问给$u,L,R$ 求$sum_{val_i in [L,R]} dis_(u,i)$
思路:
1. 由于$[L,R]$可以转化为$[0,R]-[0,L-1]$ 考虑使用主席树
题中所求可以转化为$sum _{val_i in [L,R]} dis_u+dis_i-2*dis_{lca}$ 前两项很容易计算
计算$sum_{i in State} dis_{lca(x,i)}$时候,可以树剖+线段树把所有集合内的点$i$到根的路径上的点+1
线段树上每个点点权为该点连向父亲的边的边权 因为是主席树所以需要标记永久化
然后每次查询的时候查一下主席树上该点到根的路径上的权值和
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17 #define inf 1LL<<60 18 #define rk rnk[i] 19 #define rkk rnk[i-1] 20 #define MAXN 200100 21 #define MOD 998244353 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,q,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],rnk[MAXN],tot,cnt,v[MAXN],rt[MAXN]; 31 int fa[MAXN],sz[MAXN],hvs[MAXN],bl[MAXN],tag[MAXN<<7],nums[MAXN],dep[MAXN],dfn[MAXN]; 32 ll A,ans,sum[MAXN<<7],deps[MAXN],sume[MAXN]; 33 int ls[MAXN<<7],rs[MAXN<<7];struct data{int id,val;}g[MAXN]; 34 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 35 bool operator < (data a,data b) {return a.val<b.val;} 36 void dfs(int x,int pa) 37 { 38 fa[x]=pa,sz[x]=1;ren if(to[i]^pa) 39 {dep[to[i]]=dep[x]+val[i],v[to[i]]=val[i];dfs(to[i],x),sz[x]+=sz[to[i]];if(sz[hvs[x]]<sz[to[i]]) hvs[x]=to[i];} 40 } 41 void Dfs(int x,int anc) {dfn[x]=++cnt,sume[cnt]=v[x],bl[x]=anc;if(!hvs[x]) return ;Dfs(hvs[x],anc);ren if(to[i]^hvs[x]&&to[i]^fa[x]) Dfs(to[i],to[i]);} 42 void mdf(int &k,int kk,int l,int r,int a,int b) 43 { 44 k=++tot,sum[k]=sum[kk],tag[k]=tag[kk],ls[k]=ls[kk],rs[k]=rs[kk]; 45 if(l==a&&r==b) {tag[k]++;return ;}int mid=l+r>>1;sum[k]+=sume[b]-sume[a-1]; 46 if(b<=mid) mdf(ls[k],ls[kk],l,mid,a,b);else if(a>mid) mdf(rs[k],rs[kk],mid+1,r,a,b); 47 else {mdf(ls[k],ls[kk],l,mid,a,mid);mdf(rs[k],rs[kk],mid+1,r,mid+1,b);} 48 } 49 ll query(int k,int l,int r,int a,int b) 50 { 51 if(!k) return 0LL;if(l==a&&r==b) return sum[k]+tag[k]*(sume[r]-sume[l-1]);int mid=l+r>>1; 52 ll tmp=(sume[b]-sume[a-1])*tag[k];if(b<=mid) return tmp+query(ls[k],l,mid,a,b); 53 else if(a>mid) return tmp+query(rs[k],mid+1,r,a,b); 54 else return tmp+query(ls[k],l,mid,a,mid)+query(rs[k],mid+1,r,mid+1,b); 55 } 56 void work(int i,int x) 57 { 58 rt[rk]=rt[rkk]; 59 for(;bl[x]!=1;x=fa[bl[x]]) mdf(rt[rk],rt[rk],1,n,dfn[bl[x]],dfn[x]); 60 mdf(rt[rk],rt[rk],1,n,1,dfn[x]); 61 } 62 void solve(int x,int L,int R) 63 { 64 L=lower_bound(g+1,g+n+1,(data){1,L})-g,R=upper_bound(g+1,g+n+1,(data){1,R})-g; 65 L=rnk[L]-1,R= R>n?rnk[n]:rnk[R]-1,ans=deps[R]-deps[L]+1LL*(nums[R]-nums[L])*dep[x]; 66 for(;bl[x]!=1;x=fa[bl[x]]) ans-=2LL*(query(rt[R],1,n,dfn[bl[x]],dfn[x])-query(rt[L],1,n,dfn[bl[x]],dfn[x])); 67 ans-=2LL*(query(rt[R],1,n,1,dfn[x])-query(rt[L],1,n,1,dfn[x])); 68 printf("%lld ",ans); 69 } 70 int main() 71 { 72 n=read(),q=read(),A=read();rep(i,1,n) g[i].id=i,g[i].val=read(); 73 ll a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 74 cnt=0;dfs(1,1);Dfs(1,1);cnt=0,g[0].val=-1;sort(g+1,g+n+1); 75 rep(i,1,n) 76 { 77 if(g[i].val!=g[i-1].val) cnt++;rnk[i]=cnt;sume[i]+=sume[i-1]; 78 nums[rk]=nums[rkk]+1,deps[rk]=deps[rkk]+dep[g[i].id]; 79 } 80 rep(i,1,n) work(i,g[i].id); 81 while(q--) {c=read(),a=read(),b=read();(a+=ans)%=A,(b+=ans)%=A;if(a>b) swap(a,b);solve(c,a,b);} 82 }
2.依然是差分 建立点分树
则答案可以沿着点分树暴力想上从$node_{start}$开始跳,分别统计每个点为$lca$的距离
在构建点分树的时候顺便统计该点分树子树内所有点到这个点的距离之和以及到这个点的父亲的距离之和
则每个点的答案为$sum_{val_i in [L,R]} (sum dis(x,i)-sum dis(fa_x,i)) + cnt imes (dis(x,node_{start}-dis(fa_x,node_{start}))$
为了方便使用$vector$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren for(int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define ull unsigned long long 17 #define inf 2139062143 18 #define MAXN 200100 19 #define MOD 998244353 20 using namespace std; 21 inline int read() 22 { 23 int x=0,f=1;char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 25 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 int n,q,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt,v[MAXN],sz[MAXN]; 29 int vis[MAXN],Sum,Mx,rt,mx[MAXN],dfn[MAXN],f[MAXN<<1][18],l2[MAXN<<1],fa[MAXN]; 30 ll A,ans,dis[MAXN];struct data{int val,num;ll sum,sumf;};vector <data> vec[MAXN]; 31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 32 void upd(data a,data &b) {b.sum+=a.sum,b.sumf+=a.sumf,b.num+=a.num;} 33 bool operator < (data a,data b) {return a.val<b.val;} 34 bool cmp(int a,int b) {return dis[a]<dis[b];} 35 void dfs(int x,int pa){dfn[x]=++cnt,f[cnt][0]=x;ren if(to[i]^pa) dis[to[i]]=dis[x]+val[i],dfs(to[i],x),f[++cnt][0]=x;} 36 void getrt(int x,int pa) 37 { 38 mx[x]=0,sz[x]=1;ren if(to[i]^pa&&!vis[to[i]]) getrt(to[i],x),sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]); 39 mx[x]=max(sz[x],Sum-mx[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 40 } 41 ll calc(int a,int b) 42 { 43 if(!a) return 0;if(dfn[a]>dfn[b]) swap(a,b);int t=l2[dfn[b]-dfn[a]+1]; 44 return dis[a]+dis[b]-2*dis[min(f[dfn[a]][t],f[dfn[b]-(1<<t)+1][t],cmp)]; 45 } 46 void Get(int x,int pa) 47 { 48 vec[rt].push_back((data){v[x],1,calc(rt,x),calc(fa[rt],x)}); 49 ren if(to[i]^pa&&!vis[to[i]]) Get(to[i],x); 50 } 51 void work(int x) 52 { 53 vis[x]=1;Get(x,0);vec[x].push_back((data){-1,0,0,0}); 54 sort(vec[x].begin(),vec[x].end());rep(i,1,vec[x].size()-1) upd(vec[x][i-1],vec[x][i]); 55 ren if(!vis[to[i]]) Sum=sz[to[i]],Mx=inf,getrt(to[i],0),fa[rt]=x,work(rt); 56 } 57 void solve(int x,int L,int R) 58 { 59 vector<data>:: iterator l,r;ans=0LL; 60 for(int i=x;i;i=fa[i]) 61 { 62 l=lower_bound(vec[i].begin(),vec[i].end(),(data){L,0,0,0});l--; 63 r=upper_bound(vec[i].begin(),vec[i].end(),(data){R,0,0,0});r--; 64 ans+=r->sum-l->sum+(r->num-l->num)*calc(i,x); 65 if(fa[i]) ans-=r->sumf-l->sumf+(r->num-l->num)*calc(fa[i],x); 66 } 67 printf("%lld ",ans); 68 } 69 int main() 70 { 71 n=read(),q=read(),A=read();rep(i,1,n) v[i]=read();rep(i,2,n<<1) l2[i]=l2[i>>1]+1; 72 ll a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 73 cnt=0;dfs(1,0);rep(j,1,17) rep(i,1,cnt) 74 if(i+(1<<j)-1<=cnt) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1],cmp);else break; 75 Sum=n,Mx=inf;getrt(1,0);work(rt); 76 while(q--) {c=read(),a=read(),b=read();(a+=ans)%=A,(b+=ans)%=A;if(a>b) swap(a,b);solve(c,a,b);} 77 }
bzoj 4016 最短路径树问题
题目大意:
求出一个图的最短路径树,要求从1开始的字典序最小,求在树上点数为k的路径中最长的路径长度以及有多少个最长路径
思路:
求出一个最短路径树且字典序最小,可以先用$dij$求出最短路径图,在这个图上每个点的儿子按照字典序排序,$dfs$即可求出要求的树
之后就是点分治裸题了,顺便维护一下数量即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 13 #define ren dwn(i,vec[x].size()-1,0) 14 #define ren1 for(int i=g1.fst[x];i;i=g1.nxt[i]) 15 #define ren2 for(int i=g2.fst[x];i;i=g2.nxt[i]) 16 #define Fill(x,t) memset(x,t,sizeof(x)) 17 #define ll long long 18 #define ull unsigned long long 19 #define inf 2139062143 20 #define V1 g1.to[i] 21 #define V2 g2.to[i] 22 #define MAXN 30100 23 #define MOD 998244353 24 using namespace std; 25 inline int read() 26 { 27 int x=0,f=1;char ch=getchar(); 28 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 29 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 30 return x*f; 31 } 32 int n,m,k,vis[MAXN],dis[MAXN],Sum,Mx,rt,mx[MAXN],sz[MAXN]; 33 int g[MAXN],d[MAXN],c[MAXN],num[MAXN],Dep,DEP,ans;ll tot; 34 struct node{int id,val;};vector <node> vec[MAXN]; 35 struct data{int num,dis;}; 36 bool operator < (node a,node b) {return a.val>b.val;} 37 struct graph 38 { 39 int fst[MAXN],nxt[MAXN<<2],to[MAXN<<2],val[MAXN<<2],cnt; 40 graph(){memset(fst,0,sizeof(fst));cnt=0;} 41 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 42 }g1,g2; 43 priority_queue <node> q; 44 void dij() 45 { 46 Fill(dis,127);dis[1]=0;q.push((node){1,0});int x; 47 while(!q.empty()) 48 { 49 x=q.top().id;q.pop();if(vis[x]) continue;vis[x]=1; 50 ren1 if(dis[x]==dis[V1]+g1.val[i]) vec[V1].push_back((node){g1.val[i],x}); 51 ren1 if(dis[V1]>dis[x]+g1.val[i]) dis[V1]=dis[x]+g1.val[i],q.push((node){V1,dis[V1]}); 52 } 53 } 54 void build(int x) 55 { 56 vis[x]=1;node t; 57 ren {t=vec[x][i];if(!vis[t.val]) g2.add(x,t.val,t.id),g2.add(t.val,x,t.id),build(t.val);} 58 } 59 void getrt(int x,int pa) 60 { 61 mx[x]=0,sz[x]=1;ren2 if(V2^pa&&!vis[V2]) getrt(V2,x),sz[x]+=sz[V2],mx[x]=max(mx[x],sz[V2]); 62 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 63 } 64 void Get(int x,int pa,int dep,int dis) 65 { 66 if(g[dep]<dis) g[dep]=dis,c[dep]=1;else if(g[dep]==dis) c[dep]++; 67 Dep=max(Dep,dep);ren2 if(V2^pa&&!vis[V2]) Get(V2,x,dep+1,dis+g2.val[i]); 68 } 69 void solve(int x) 70 { 71 rep(i,1,DEP) d[i]=num[i]=0;DEP=0;num[0]=c[0]=1; 72 vis[x]=1;ren2 if(!vis[V2]) 73 { 74 rep(i,1,Dep) g[i]=c[i]=0;Dep=0; 75 Get(V2,x,1,g2.val[i]);Dep=min(Dep,k-1),DEP=max(DEP,Dep); 76 rep(i,1,Dep) 77 if(g[i]+d[k-i-1]>ans) ans=g[i]+d[k-i-1],tot=num[k-i-1]*c[i]; 78 else if(g[i]+d[k-i-1]==ans) tot+=num[k-i-1]*c[i]; 79 rep(i,1,Dep) if(d[i]<g[i]) d[i]=g[i],num[i]=c[i];else if(d[i]==g[i]) num[i]+=c[i]; 80 } 81 ren2 if(!vis[V2]) Sum=sz[V2],Mx=inf,rt=0,getrt(V2,0),solve(rt); 82 } 83 int main() 84 { 85 n=read(),m=read(),k=read();int a,b,c;while(m--) a=read(),b=read(),c=read(),g1.add(a,b,c),g1.add(b,a,c); 86 dij();rep(i,1,n) sort(vec[i].begin(),vec[i].end());Fill(vis,0); 87 build(1);Sum=n,Mx=inf;Fill(vis,0);getrt(1,0);solve(rt);printf("%d %d ",ans,tot); 88 }
bzoj 1758 重建计划
题目大意:
求路径上边数在$[L,R]$中,边权平均值最大的路径
思路:
这种平均值的东西首先肯定要二分一下平均值
考虑合并,对于每个新的子树,记录一下每个深度的最长路径
这样的话每个深度$i$可以由$[L-i,R-i]$这个区间的路径转移过来
维护一个单调队列即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 #include<complex> 12 #include<iomanip> 13 #define Fill(a,x) memset(a,x,sizeof(a)) 14 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 15 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 16 #define ren for(int i=fst[x];i;i=nxt[i]) 17 #define inf 2139062143 18 #define ll long long 19 #define ull unsigned long long 20 #define MAXN 100100 21 #define MOD 998244353 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 const double eps=1e-4; 31 struct data {int num,bl,val;}g[MAXN]; 32 bool operator < (data a,data b) {return a.num<b.num;} 33 int n,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt,sz[MAXN],mx[MAXN],tmp[MAXN],son; 34 double ans,res[MAXN],maxv,d[MAXN]; 35 int L,R,Sum,Mx,rt,len,vis[MAXN],val[MAXN<<1],hd,tl,q[MAXN],Dep,DEP,mxd[MAXN]; 36 bool cmp(int a,int b) {return mxd[to[a]]<mxd[to[b]];} 37 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;maxv=max(maxv,(double)w);} 38 void getrt(int x,int pa) 39 { 40 mx[x]=mxd[x]=0,sz[x]=1;ren if(to[i]^pa&&!vis[to[i]]) 41 getrt(to[i],x),mxd[x]=max(mxd[x],mxd[to[i]]),sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]); 42 mxd[x]++,mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 43 } 44 double l,r,mid; 45 void Get(int x,int pa,int dep,double dis) 46 { 47 if(dep>R) return ; 48 Dep=max(Dep,dep),d[dep]=max(d[dep],dis); 49 ren if(to[i]^pa&&!vis[to[i]]) Get(to[i],x,dep+1,dis+val[i]-mid); 50 } 51 int cheq(int x) 52 { 53 son=0;ren if(!vis[to[i]]) tmp[++son]=i;sort(tmp+1,tmp+son+1,cmp); 54 rep(i,1,DEP) res[i]=-inf;DEP=0; 55 rep(i,1,son) 56 { 57 rep(i,1,Dep) d[i]=-inf;Dep=0;Get(to[tmp[i]],x,1,val[tmp[i]]-mid); 58 hd=1,tl=0;int pos=max(L-Dep,0);dwn(j,Dep,1) 59 { 60 while(pos<=DEP&&pos+j<=R) {while(hd<=tl&&res[pos]>res[q[tl]]) tl--;q[++tl]=pos++;} 61 while(hd<=tl&&q[hd]+j<L) hd++; 62 if(hd<=tl&&res[q[hd]]+d[j]>=0) return 1; 63 } 64 rep(j,1,Dep) res[j]=max(res[j],d[j]);DEP=max(DEP,Dep); 65 } 66 return 0; 67 } 68 void calc(int x) 69 { 70 vis[x]=1;l=ans,r=maxv; 71 for(;mid=(l+r)/2.0,l<r+eps;) if(cheq(x)) l=mid+eps;else r=mid-eps; 72 ans=max(ans,l-eps); 73 } 74 void div(int x){calc(x);ren if(!vis[to[i]]) Sum=sz[to[i]],Mx=n+1,getrt(to[i],x),div(rt);} 75 int main() 76 { 77 n=read(),L=read(),R=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 78 rep(i,1,n) res[i]=d[i]=-inf;Sum=n,Mx=n+1;getrt(1,0);div(rt);printf("%.3lf ",ans); 79 }
bzoj 1095 捉迷藏
题目大意:
一棵树,每个点有黑白两个颜色 支持单点修改改颜色与查询最远两个黑点的距离
思路:
建立点分树,对于每个点开两个堆,分别维护点分树子树内所有点到分治树上$fa$的距离以及分治树上儿子的第一个堆的堆顶
再维护一个全局堆维护每个点第二个堆的堆顶
这样全局暴力,每次修改改一个链即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 #include<complex> 12 #include<iomanip> 13 #define Fill(a,x) memset(a,x,sizeof(a)) 14 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 15 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 16 #define ren for(int i=fst[x];i;i=nxt[i]) 17 #define inf 2139062143 18 #define ll long long 19 #define ull unsigned long long 20 #define MAXN 100100 21 #define MOD 998244353 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,Q,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],l2[MAXN<<1],f[MAXN<<1][18],tot,in[MAXN]; 31 int dep[MAXN],fa[MAXN],c[MAXN],cnt,mx[MAXN],rt,Sum,Mx,sz[MAXN],vis[MAXN]; 32 struct Heap 33 { 34 priority_queue <int> A,B; 35 void push(int x) {A.push(x);}void del(int x) {B.push(x);} 36 int size() {return A.size()-B.size();}int empty(){return size()==0;} 37 int top(){while((!B.empty())&&A.top()==B.top()) A.pop(),B.pop();return A.top();} 38 void pop(){while((!B.empty())&&A.top()==B.top()) A.pop(),B.pop();A.pop();} 39 int sum(){int res,tmp;tmp=top();pop();res=tmp+top();push(tmp);return res;} 40 }q[MAXN],qs[MAXN],ans; 41 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 42 void mdf(Heap &a,int val){if(a.size()<2) return ;if(val) ans.push(a.sum());else ans.del(a.sum());} 43 void dfs(int x,int pa) 44 { 45 in[x]=++tot,f[tot][0]=x;ren if(to[i]^pa) dep[to[i]]=dep[x]+1,dfs(to[i],x),f[++tot][0]=x; 46 } 47 bool cmp(int a,int b) {return dep[a]<dep[b];} 48 int dis(int a,int b) 49 { 50 if(in[a]>in[b]) swap(a,b);int t=l2[in[b]-in[a]+1]; 51 return dep[a]+dep[b]-dep[min(f[in[a]][t],f[in[b]-(1<<t)+1][t],cmp)]*2; 52 } 53 void getrt(int x,int pa) 54 { 55 mx[x]=0,sz[x]=1;ren if(to[i]^pa&&!vis[to[i]]) 56 getrt(to[i],x),sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]); 57 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x; 58 } 59 void Get(int x,int pa,int anc) 60 { 61 q[anc].push(dis(x,fa[anc])); 62 ren if(to[i]^pa&&!vis[to[i]]) Get(to[i],x,anc); 63 } 64 void Div(int x) 65 { 66 vis[x]=1;qs[x].push(0);Get(x,0,x);qs[fa[x]].push(q[x].top()); 67 ren if(!vis[to[i]]) Sum=sz[to[i]],Mx=n+1,getrt(to[i],x),fa[rt]=x,Div(rt); 68 mdf(qs[x],1); 69 } 70 void On(int x) 71 { 72 mdf(qs[x],0);qs[x].del(0);mdf(qs[x],1);cnt--; 73 for(int i=x;i;i=fa[i]) 74 { 75 mdf(qs[fa[i]],0);if(!q[i].empty()) qs[fa[i]].del(q[i].top()); 76 q[i].del(dis(x,fa[i]));if(!q[i].empty()) qs[fa[i]].push(q[i].top()); 77 mdf(qs[fa[i]],1); 78 } 79 } 80 void Off(int x) 81 { 82 mdf(qs[x],0);qs[x].push(0);mdf(qs[x],1);cnt++; 83 for(int i=x;i;i=fa[i]) 84 { 85 mdf(qs[fa[i]],0);if(!q[i].empty()) qs[fa[i]].del(q[i].top()); 86 q[i].push(dis(x,fa[i]));if(!q[i].empty()) qs[fa[i]].push(q[i].top()); 87 mdf(qs[fa[i]],1); 88 } 89 } 90 int main() 91 { 92 n=read();int a,b;rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a); 93 rep(i,2,n<<1) l2[i]=l2[i>>1]+1;dfs(1,0); 94 rep(j,1,17) rep(i,1,tot) 95 if(i+(1<<j)-1<=tot) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1],cmp);else break; 96 Sum=n,Mx=n+1;getrt(1,0);Div(rt);cnt=n; 97 Q=read();char s[10];while(Q--) 98 { 99 scanf("%s",s); 100 if(s[0]=='G') {if(cnt<=1) printf("%d ",cnt-1);else printf("%d ",ans.top());} 101 else {a=read();if(c[a]==1) Off(a);else On(a);c[a]^=1;} 102 } 103 }