简单分块做法申请添加题解
查看原帖
简单分块做法申请添加题解
802681
wangziyue_AK楼主2024/11/10 20:38

现有题解只有动态点分治和树剖加主席树两种做法,都需要高难度的前置知识和代码能力。而本做法只需要分块、ST表和换根DP。码量主要靠多个简单部分堆砌,实现优良完全没有调试难度,对代码能力要求也不高。 题解链接:我的题解 代码:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back 
typedef pair<int,int> pr;
#define fi first
#define se second
typedef long long ll;
const int N=1.5e5+5;
const int M=395;
const ll inf=1e15+7ll;
const int N3=N<<1;
vector<pr> g[N];
struct LCA{	
	int mx,cnt,rk[N3],a[N3],dep[N3],dfn[N3],rnk[N3];
	ll dis[N3];
	int lg[N3],mi[21],st[21][N<<1],id[21][N3];
	void dfs(int u,int fa){
		dep[u]=dep[fa]+1,dfn[u]=++cnt;
		a[cnt]=dep[u],rnk[cnt]=u;
		for(pr it:g[u]){
			int v=it.fi,w=it.se;
			if(v==fa) continue;
			dis[v]=dis[u]+w;
			dfs(v,u);
			a[++cnt]=dep[u],rnk[cnt]=u;
		}
	}
	void init_ST(){
		lg[1]=0;
		for(int i=2;i<=cnt;i++) lg[i]=lg[i>>1]+1;
		mx=lg[cnt];
		mi[0]=1;
		for(int i=1;i<=mx;i++) mi[i]=mi[i-1]<<1;
		for(int i=1;i<=cnt;i++) st[0][i]=a[i],id[0][i]=rnk[i];
		for(int i=1;i<=mx;i++){
			for(int j=1;j+mi[i]-1<=cnt;j++){
				int nx=j+mi[i-1];
				if(st[i-1][j]<st[i-1][nx]){
					st[i][j]=st[i-1][j],id[i][j]=id[i-1][j];
				}else{
					st[i][j]=st[i-1][nx],id[i][j]=id[i-1][nx];
				}
			}
		}
	}
	inline int lca(int u,int v){
		int l=dfn[u],r=dfn[v];
		if(l>r) swap(l,r);
		int k=lg[r-l+1],res;
		int nx=r-mi[k]+1;
		if(st[k][l]<st[k][nx]) res=id[k][l];
		else res=id[k][nx];
		return res;
	}
	inline ll d(int u,int v){
		return dis[u]+dis[v]-(dis[lca(u,v)]<<1);
	}
	void init(int rt){
		cnt=0;
		dfs(rt,0);init_ST();
	}
}tr;
struct dfsdp{
	ll f[N];int sz[N];
	void dfs1(int u,int fa){
		for(pr it:g[u]){
			int v=it.fi,w=it.se;
			if(v==fa) continue;
			dfs1(v,u);
			sz[u]+=sz[v];
			f[u]+=f[v]+1ll*w*sz[v];
		}
	}
	void dfs2(int u,int fa){
		for(pr it:g[u]){
			int v=it.fi,w=it.se;
			if(v==fa) continue;
			ll k=f[u]-f[v]-1ll*w*sz[v];
			f[v]+=k,f[v]+=1ll*(sz[1]-sz[v])*w;
			dfs2(v,u);
		}
	}
	inline void getdis(){
		dfs1(1,0),dfs2(1,0);
	}
}xx;
int n,m,ans,cnt,l[M],r[M],bel[N];ll ax[(int)(M/1.5)][N];
struct node{ int x,id; }a[N];
inline bool cmp(node ax,node ay){ return ax.x<ay.x;}
inline void bld(int x){
	for(int i=1;i<=n;i++) xx.f[i]=xx.sz[i]=0;
	for(int i=l[x];i<=r[x];i++) xx.sz[a[i].id]=1;
	xx.getdis();
	for(int i=1;i<=n;i++) ax[x][i]=xx.f[i];
}
inline ll get(int li,int ri,int x){
	ll res=0;
	for(int i=li;i<=ri;i++) res+=tr.d(x,a[i].id);
	return res;
}
inline ll qiu(int li,int ri,int x){
	if(li>ri) return 0;
	int bl=bel[li],br=bel[ri];
	if(bl==br) return get(li,ri,x);
	ll res=get(li,r[bl],x)+get(l[br],ri,x);
	for(int i=bl+1;i<br;i++) res+=ax[i][x];
	return res;
}
void init(){
	int k=min(n,(int)(sqrt(n)*1.5)),nw=1,la=0;
	while(nw<n){
		nw=min(nw+k,n),cnt++;
		l[cnt]=la,r[cnt]=nw;
		for(int i=la;i<=nw;i++) bel[i]=cnt;
		la=nw+1;
	}
	for(int i=1;i<=cnt;i++) bld(i);
}
struct bs{
	inline int findl(int x){
		int l=1,r=n,pos=n+1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(a[mid].x>=x) r=mid-1,pos=mid;
			else l=mid+1;
		}
		return pos;
	}
	inline int findr(int x){
		int l=1,r=n,pos=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(a[mid].x<=x) l=mid+1,pos=mid;
			else r=mid-1;
		}
		return pos;
	}
}ef;
int mod;
int main(){
	scanf("%d%d%d",&n,&m,&mod);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].x);a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	int u,v,w;
	for(int i=1;i<n;i++){
		scanf("%d%d%d",&u,&v,&w);
		g[u].pb({v,w}),g[v].pb({u,w});
	}
	tr.init(1);
	init();
	int li,ri,aa,bb;
	ll las=0;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&aa,&bb);
		int li=(las+aa)%mod,ri=(las+bb)%mod;
		if(li>ri) swap(li,ri);
		int nl=ef.findl(li),nr=ef.findr(ri);
//		printf("111 l:%d r:%d\n",li,ri);
//		printf("000 L:%d R:%d\n",nl,nr);
		las=qiu(nl,nr,u);
		printf("%lld\n",las);
	}
    return 0;
}
2024/11/10 20:38
加载中...