【校內模擬】看門人(長鏈剖分)(DFS序)(ZKW線段樹)

傳送門


題解:

很顯然的長鏈剖分。

合併顯然是一個取max。

詢問顯然是一個區間詢問max。

先長鏈剖分,搞出重兒子優先的dfs序,然後上線段樹就行了。

發現只有單點修改,區間詢問max,直接上ZKW線段樹。

跑得比香港記者還快


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num; 
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=998244353;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}

template<class T>
inline void ckmax(T &a,T b){a<b?a=b:0;}

cs int N=1e6+7;

int n;

int pw[N];
inline void init_pw(){
	pw[0]=1;for(int re i=1;i<=n;++i)pw[i]=mul(pw[i-1],23333);
}

int el[N],nxt[N],to[N],ecnt;
inline void adde(int u,int v){
	nxt[++ecnt]=el[u],el[u]=ecnt,to[ecnt]=v;
}

int fa[N];
int L[N],R[N];
ll val[N],dis[N],ans[N];
int son[N],mxd[N];

void dfs1(int u,int p){
	for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]]){
		dis[v]=dis[u]+val[v];dfs1(v,u);
		if(mxd[v]+1>mxd[u]){
			mxd[u]=mxd[v]+1;
			son[u]=v;
		}
	}
}

int in[N],pos[N],clk;
void dfs2(int u,int p){
	pos[in[u]=++clk]=u;
	if(son[u])dfs2(son[u],u);
	for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])if(v!=son[u])dfs2(v,u);
}

namespace SGT{
	cs int N=1<<21|7;
	ll mx[N];int M;
	
	inline void build(int n){
		for(M=1;M<=n+1;M<<=1);
		for(int re i=M+1;i<=M+n;++i)mx[i]=dis[pos[i-M]];
		for(int re i=M-1;i;--i)mx[i]=std::max(mx[i<<1],mx[i<<1|1]);
	}
	inline void cmax(int p,int p2){
		p+=M,p2+=M;if(mx[p]>=mx[p2])return ;mx[p]=mx[p2];
		for(p>>=1;p;p>>=1)mx[p]=std::max(mx[p<<1],mx[p<<1|1]);
	}
	inline ll query(int p){return mx[p+M];}
	inline ll query(int l,int r){
		ll ans=0;
		for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
			if(l&1^1)ckmax(ans,mx[l^1]);
			if(r&1)  ckmax(ans,mx[r^1]);
		}
		return ans;
	}
}

void dfs3(int u,int p){
	ans[u]=-1;
	if(!son[u]){return ;}
	dfs3(son[u],u);
	if(L[u]<=mxd[u])ans[u]=SGT::query(in[u]+L[u],in[u]+std::min(mxd[u],R[u]))-dis[u];
	for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])if(v!=son[u]){
		dfs3(v,u);--in[v],++mxd[v];
		for(int re i=1;i<=mxd[v];++i){
			if(L[u]<=i&&i<=R[u])ckmax(ans[u],SGT::query(in[v]+i)-dis[u]);
			int l=std::max(1,L[u]-i);
			int r=std::min(mxd[u],R[u]-i);
			if(l>r)continue;
			ckmax(ans[u],SGT::query(in[v]+i)+SGT::query(in[u]+l,in[u]+r)-dis[u]*2);
		}
		for(int re i=1;i<=mxd[v];++i)SGT::cmax(in[u]+i,in[v]+i);
	}
}

signed main(){
#ifdef zxyoi
	freopen("watchdog.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
	freopen("watchdog.in","r",stdin);freopen("watchdog.out","w",stdout);
#endif
#endif
	n=gi();init_pw();
	for(int re i=1;i<=n;++i)L[i]=gi(),R[i]=gi();
	for(int re i=2;i<=n;++i){
		adde(fa[i]=gi(),i);
		val[i]=gi();
	}
	dfs1(1,0);dfs2(1,0);SGT::build(n);
	dfs3(1,0);int res=0;
	for(int re i=1;i<=n;++i){
		int t=ans[i]==-1?mod-1ll:(ans[i]%mod);
	//	cerr<<"i : "<<i<<" "<<ans[i]<<"\n";
		Inc(res,mul(t,pw[n-i]));
	}
	cout<<res<<"\n";
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章