【系列】 点分治

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 }
View Code

但是树形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 }
View Code

 

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 }
View Code

 

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\n",dp[i]);
62 }
View Code

 

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\n",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 }
View Code

2.依然是差分 建立点分树

则答案可以沿着点分树暴力想上从$node_{start}$开始跳,分别统计每个点为$lca$的距离

在构建点分树的时候顺便统计该点分树子树内所有点到这个点的距离之和以及到这个点的父亲的距离之和

则每个点的答案为$\sum_{val_i \in [L,R]} (\sum dis(x,i)-\sum dis(fa_x,i)) + cnt \times (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\n",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 }
View Code

 

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\n",ans,tot);
88 }
View Code

 

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\n",ans);
79 }
View Code

 

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\n",cnt-1);else printf("%d\n",ans.top());}
101         else {a=read();if(c[a]==1) Off(a);else On(a);c[a]^=1;}
102     }
103 }
View Code

 

转载于:https://www.cnblogs.com/yyc-jack-0920/p/10160043.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值