博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【系列】 点分治
阅读量:5069 次
发布时间:2019-06-12

本文共 18987 字,大约阅读时间需要 63 分钟。

bzoj 2152 聪聪可可

题目大意:

求树上边权和为3的倍数的路径的条数

思路:

点分治练习题 

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long16 #define ull unsigned long long17 #define inf 100000000018 #define MAXN 10010019 #define MOD 99824435320 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]
View Code

但是树形dp明显更加优秀

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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)%316 #define ll long long17 #define ull unsigned long long18 #define inf 100000000019 #define MAXN 2001020 #define MOD 99824435321 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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long16 #define ull unsigned long long17 #define inf 100000000018 #define MAXN 10010019 #define MOD 99824435320 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]
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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long16 #define ull unsigned long long17 #define inf 1LL<<6018 #define MAXN 20010019 #define MOD 99824435320 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]
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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long16 #define ull unsigned long long17 #define inf 1LL<<6018 #define rk rnk[i]19 #define rkk rnk[i-1]20 #define MAXN 20010021 #define MOD 99824435322 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
>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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long16 #define ull unsigned long long17 #define inf 213906214318 #define MAXN 20010019 #define MOD 99824435320 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 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
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<
:: 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<
<=cnt) f[i][j]=min(f[i][j-1],f[i+(1<
b) swap(a,b);solve(c,a,b);}77 }
View Code

 

bzoj 4016 最短路径树问题

题目大意:

求出一个图的最短路径树,要求从1开始的字典序最小,求在树上点数为k的路径中最长的路径长度以及有多少个最长路径

思路:

求出一个最短路径树且字典序最小,可以先用$dij$求出最短路径图,在这个图上每个点的儿子按照字典序排序,$dfs$即可求出要求的树

之后就是点分治裸题了,顺便维护一下数量即可

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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 long18 #define ull unsigned long long19 #define inf 213906214320 #define V1 g1.to[i]21 #define V2 g2.to[i]22 #define MAXN 3010023 #define MOD 99824435324 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
vec[MAXN];35 struct data{ int num,dis;};36 bool operator < (node a,node b) { return a.val>b.val;}37 struct graph38 {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
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]
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]
View Code

 

bzoj 1758 重建计划

题目大意:

求路径上边数在$[L,R]$中,边权平均值最大的路径

思路:

这种平均值的东西首先肯定要二分一下平均值

考虑合并,对于每个新的子树,记录一下每个深度的最长路径

这样的话每个深度$i$可以由$[L-i,R-i]$这个区间的路径转移过来

维护一个单调队列即可

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
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 213906214318 #define ll long long19 #define ull unsigned long long20 #define MAXN 10010021 #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
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
=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
View Code

 

bzoj 1095 捉迷藏

题目大意:

一棵树,每个点有黑白两个颜色 支持单点修改改颜色与查询最远两个黑点的距离

思路:

建立点分树,对于每个点开两个堆,分别维护点分树子树内所有点到分治树上$fa$的距离以及分治树上儿子的第一个堆的堆顶

再维护一个全局堆维护每个点第二个堆的堆顶

这样全局暴力,每次修改改一个链即可

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
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
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]
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<
>1]+1;dfs(1,0); 94 rep(j,1,17) rep(i,1,tot) 95 if(i+(1<
<=tot) f[i][j]=min(f[i][j-1],f[i+(1<
View Code

 

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

你可能感兴趣的文章
html中的meta标签属性
查看>>
js中的script标签属性
查看>>
前端网页全局属性
查看>>
html中代替空格、大于号、小于号等字符编码
查看>>
html5语义化标签
查看>>
前端img标签属性
查看>>
iOS APP打包上传到AppStore的最新步骤
查看>>
iOS CALayer之CAEmitterLayer粒子发射器的神奇效果
查看>>
iOS学习笔记-084.粒子效果——路径移动
查看>>
iOS Bezier曲线
查看>>
【ogg三】日常运维篇:清理归档日志,ogg进程注册服务,定期备份数据库
查看>>
从零搭建企业大数据分析和机器学习平台-技术栈介绍(三)
查看>>
shell——Day3
查看>>
元素居中的六种方法
查看>>
超低功耗研发-STM32L151C8T6芯片(一)时钟系统概述
查看>>
软件外包平台
查看>>
pandas入门之DataFrame
查看>>
爬虫github_博客资源
查看>>
爬虫加密解密工具类在线网站
查看>>
爬虫mysql,redis重新连接和关闭连接
查看>>