把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5311 [Ynoi2011] 成都七中

题面传送门

首先考虑暴力怎么做。按照UNRD2T2找到每个联通块最高点的套路,我们可以找到每个询问点的祖先中,这个点到祖先路径上的点全部位于\([l,r]\)区间中的最浅的祖先,那么这个点所在的联通块可以表示为这个点子树内,到这个点路径上点全部位于\([l,r]\)内的点所构成的联通块,然后可以暴力数颜色。

我们发现整个预处理部分如果树是随机的就可以过了,但是这个高度显然不随机。

发现这个问题对树的形态要求不是很高,考虑建立点分树,然后预处理树上倍增可以快速查询,就可以暴力往上跳找到这个祖先,然后也可以暴力遍历子树找到每个点到根节点取值区间,当前的询问区间要包含这个区间才可以算入答案。

在线不太好做,考虑离线到每个点分树上面的点上,然后将询问和点都按照右端点排序,这样的话可以对右端点扫描线,并且维护每个颜色最近的左端点,就可以用一个树状数组二维数点了。

时间复杂度\(O(n\log ^2n+q\log n)\),常数挺小的毕竟瓶颈在树状数组和排序。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=100000+5,M=(N*200)+5,K=(1<<16)+5,mod=998244353,M1=998244353,M2=1e9+7,Mod=mod-1;const db eps=1e-5;
int n,m,W[N],x,y,z,Ans[N];vector<int> S[N];
struct Ques{int x,y,z;}D[N];vector<Ques> Q[N];bool cmp(Ques x,Ques y){return x.y<y.y;}
namespace DIS{
	int fa[N][20],lg[N],Mx[N][20],Mi[N][20],d[N];
	void Make(int x,int La){fa[x][0]=La;Mx[x][0]=Mi[x][0]=x;d[x]=d[La]+1;for(int i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1],Mx[x][i]=max(Mx[x][i-1],Mx[fa[x][i-1]][i-1]),Mi[x][i]=min(Mi[x][i-1],Mi[fa[x][i-1]][i-1]);for(int i:S[x]) i^La&&(Make(i,x),0);}
	void BD(){for(int i=2;i<=n;i++) lg[i]=lg[i/2]+1;Make(1,0);}
	pair<int,int> Qry(int x,int y){int Xm=0,Im=1e9;d[x]<d[y]&&(swap(x,y),0);while(d[x]^d[y]) Xm=max(Xm,Mx[x][lg[d[x]-d[y]]]),Im=min(Im,Mi[x][lg[d[x]-d[y]]]),x=fa[x][lg[d[x]-d[y]]];if(x==y) return {min(Im,x),max(Xm,x)};for(int i=lg[d[x]];~i;i--) fa[x][i]^fa[y][i]&&(Xm=max(Xm,max(Mx[x][i],Mx[y][i])),Im=min(Im,min(Mi[x][i],Mi[y][i])),x=fa[x][i],y=fa[y][i]);return {min(Im,min(fa[x][0],min(x,y))),max(Xm,max(fa[x][0],max(x,y)))};}
} 
namespace Tree{int f[N];void Ins(int x,int y){while(x<=n) f[x]+=y,x+=x&-x;}int Qry(int x){int Ans=0;while(x) Ans+=f[x],x-=x&-x;return Ans;}}
namespace DT{
	int Dh,f[N],g[N],Ct,Rt,Si[N],fa[N],vis[N],R;vector<int> G[N];void GI(int x,int La){Ct++;for(int i:S[x]) i^La&&!vis[i]&&(GI(i,x),0);}
	void DP(int x,int La){f[x]=0;Si[x]=1;for(int i:S[x]) i^La&&!vis[i]&&(DP(i,x),Si[x]+=Si[i],f[x]=max(f[x],Si[i]));f[x]=max(f[x],Ct-Si[x]);f[x]<f[Rt]&&(Rt=x);}
	void BD(int x,int La){Ct=0;GI(x,0);Rt=0;DP(x,0);x=Rt;La&&(G[La].PB(x),fa[x]=La);vis[x]=1;for(int i:S[x]) !vis[i]&&(BD(i,x),0);}
	int Jp(int x,int l,int r){int Ans=x,Id=x;pair<int,int> Ts;while(x) Ts=DIS::Qry(x,Id),Ts.first>=l&&Ts.second<=r&&(Ans=x),x=fa[x];return Ans;}
	void Push(int x,int Id){pair<int,int> Ts=DIS::Qry(x,Id);D[++Dh]=(Ques){Ts.first,Ts.second,W[x]};for(int i:G[x]) Push(i,Id);}
	void Solve(){
		int i,j;for(i=1;i<=n;i++){
			Dh=0;Push(i,i);sort(D+1,D+Dh+1,cmp);sort(Q[i].begin(),Q[i].end(),cmp);R=1;for(Ques d:Q[i]){
				while(R<=Dh&&D[R].y<=d.y) g[D[R].z]&&(Tree::Ins(g[D[R].z],-1),0),g[D[R].z]=max(D[R].x,g[D[R].z]),Tree::Ins(g[D[R].z],1),R++;Ans[d.z]=Tree::Qry(d.y)-Tree::Qry(d.x-1);
			}for(j=1;j<R;j++) g[D[j].z]&&(Tree::Ins(g[D[j].z],-1),g[D[j].z]=0);
		} 
	}
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&W[i]);for(i=1;i<n;i++) scanf("%d%d",&x,&y),S[x].PB(y),S[y].PB(x);DIS::BD();DT::f[0]=1e9;DT::BD(1,0);
	for(i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),Q[DT::Jp(z,x,y)].PB({x,y,i});DT::Solve();for(i=1;i<=m;i++) printf("%d\n",Ans[i]);
}
posted @ 2022-08-24 21:23  275307894a  阅读(21)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end