zoukankan      html  css  js  c++  java
  • 【系列】 点分治

    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
    ",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
    ",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 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 }
    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
    ",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
    ",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
    ",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 }
    View Code
  • 相关阅读:
    第07组 Alpha冲刺(1/6)
    第07组 团队Git现场编程实战
    第07组 团队项目-需求分析报告
    团队项目-选题报告
    第二次结对编程作业
    0012---求滑动距离
    0011---绝对值函数
    0010---温度转换
    0009---乘法问题
    0008---三位数倒序问题
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10160043.html
Copyright © 2011-2022 走看看