P14380 【MX-S9-T3】「LAOI-16」天外来物 题解

题目链接:P14380 【MX-S9-T3】「LAOI-16」天外来物

首先考虑链,显然只有 $ l, r $ 恰好是编号在区间 $ [l, r] $ 的点构成的链的两个端点时才是一个极小区间(极小区间指无论让左端点加一还是右端点减一都会让联通块变的和原来不一样的区间),那树也是一样的,点 $ l, r $ 必须一个为编号最大的叶子结点,一个为编号最小的叶子结点,那定义 $ rt_l $ 代表以 $ l $ 为左节点满足 $ l $ 为编号最小/最大的叶子结点的最大的 $ r $(为什么是单调的?因为考虑会存在 $ rt_l+1 $,使得以 $ l $ 为根的树中会有两个不同的子树存在编号在 $ [l, rt_i+1] $ 的区间内的点,因此删去 $ l $ 也可以通过子树不同的那两个点的 LCA 经过),同理求出 $ lt_r $。现在相当于要求 $ \sum_{l=L}^{R} \sum_{r=l}^{R} [lt_r \le l \land rt_l \ge r] $。

对于求出 $ lt, rt $,可以使用扫描线,对于 dfn 序建线段树维护单点修改,区间最小值即可。对于计算最终答案,离线下来使用扫描线,用类似维护历史和的方法即可(维护历史和就在每一次操作后打一个代表更新历史和的 tag,然后每次下传前先更新历史和)。

代码:

#include<bits/stdc++.h>
#define time(null) chrono::steady_clock::now().time_since_epoch().count()
#define int long long
#define uint unsigned long long
#define debug() cout<<"come here\n"
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define pb push_back
#define Code return
#define by 0
#define MCYYDS ;
using namespace std;
int qpow(int a,int b,int p=INF){int ret=1;while(b){if(b&1)ret=(ret*a)%p;a=(a*a)%p;b>>=1;}return ret;}
inline int read(){int ret=0,f=1;char ch=getchar();while(ch<'0'||ch>'9')f=(ch=='-'?-1:f),ch=getchar();while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();return ret*f;}
inline void write(int x){if(x<0){putchar('-');write(-x);return ;}if(x>9)write(x/10);putchar((char)(x%10+48));}
inline void writech(int x,char ch){write(x);putchar(ch);}
int n,q,tot,dfn[500005],dfr[500005],fa[500005],rt[500005],lt[500005],ans[500005];
vector<int> e[500005],del[500005];
struct node{
	int x,id;
};
vector<node> ask[500005];
void dfs(int u,int f)
{
	fa[u]=f;
	dfn[u]=++tot;
	for(auto v:e[u])
	{
		if(v==f)continue;
		dfs(v,u);
	}
	dfr[u]=tot;
}
struct segtree{
	vector<int> mx;
	void init()
	{
		mx.assign(n<<2,0);
	}
	void clear()
	{
		for(auto &x:mx)
		{
			x=0;
		}
	}
	void update(int x,int v,int l=1,int r=n,int id=1)
	{
		if(l==r)
		{
			mx[id]=v;
			return ;
		}
		int mid=l+r>>1;
		if(x<=mid)update(x,v,l,mid,id<<1);
		else update(x,v,mid+1,r,id<<1|1);
		mx[id]=max(mx[id<<1],mx[id<<1|1]);
		return ;
	}
	int query(int ql,int qr,int l=1,int r=n,int id=1)
	{
		if(ql>qr)return 0;
		if(ql<=l&&r<=qr)return mx[id];
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret=max(ret,query(ql,qr,l,mid,id<<1));
		if(qr>mid)ret=max(ret,query(ql,qr,mid+1,r,id<<1|1));
		return ret;
	}
}trmx;
void upd2(int x,int &mx1,int &mx2)
{
	if(x>mx1)
	{
		mx2=mx1;
		mx1=x;
	}
	else if(x>mx2)mx2=x;
}
int getmx(int u,int v)
{
	if(v==fa[u])return max(trmx.query(1,dfn[u]-1),trmx.query(dfr[u]+1,n));
	return trmx.query(dfn[v],dfr[v]);
}
struct hsegtree{
	int cnt[2000005],tag[2000005],sum[2000005];
	void upd(int id,int v)
	{
		sum[id]+=v*cnt[id];
		tag[id]+=v;
	}
	void pushdown(int id)
	{
		if(!tag[id])return ;
		upd(id<<1,tag[id]);
		upd(id<<1|1,tag[id]);
		tag[id]=0;
	}
	void pushup(int id)
	{
		cnt[id]=cnt[id<<1]+cnt[id<<1|1];
		sum[id]=sum[id<<1]+sum[id<<1|1];
	}
	void update(int l,int r,int id,int x,int v)
	{
		if(l==r)
		{
			cnt[id]=v;
			return ;
		}
		pushdown(id);
		int mid=l+r>>1;
		if(x<=mid)update(l,mid,id<<1,x,v);
		else update(mid+1,r,id<<1|1,x,v);
		pushup(id);
	}
	void updh(int l,int r,int id,int ql,int qr)
	{
		if(ql<=l&&r<=qr)
		{
			upd(id,1);
			return ;
		}
		pushdown(id);
		int mid=l+r>>1;
		if(ql<=mid)updh(l,mid,id<<1,ql,qr);
		if(qr>mid)updh(mid+1,r,id<<1|1,ql,qr);
		pushup(id);
	}
	int query(int l,int r,int id,int ql,int qr)
	{
		if(ql<=l&&r<=qr)return sum[id];
		pushdown(id);
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret+=query(l,mid,id<<1,ql,qr);
		if(qr>mid)ret+=query(mid+1,r,id<<1|1,ql,qr);
		return ret;
	}
	int getpre(int x)
	{
		if(x<=0)return 0;
		return query(1,n,1,1,x);
	}
}trh;
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	n=read(),q=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		e[u].pb(v);
		e[v].pb(u);	
	}
	dfs(1,0);
	trmx.init();
	for(int u=1;u<=n;u++)
	{
		int mx1=0,mx2=0;
		for(auto v:e[u])
		{
			upd2(getmx(u,v),mx1,mx2);
		}
		lt[u]=mx2+1;
		trmx.update(dfn[u],u);
	}
	trmx.clear();
	for(int u=n;u>=1;u--)
	{
		int mx1=0,mx2=0;
		for(auto v:e[u])
		{
			upd2(getmx(u,v),mx1,mx2);
		}
		rt[u]=n-mx2;
		trmx.update(dfn[u],n-u+1);
	}
	for(int i=1;i<=n;i++)
	{
		if(rt[i]<n)del[rt[i]+1].pb(i);
	}
	for(int i=1;i<=q;i++)
	{
		int l=read(),r=read();
		ask[r].pb({r,i});
		ask[r].pb({l-1,-i});
		ask[l-1].pb({r,-i});
		ask[l-1].pb({l-1,i});
	}
	for(int i=0;i<=n;i++)
	{
		if(i)
		{
			for(auto x:del[i])
			{
				trh.update(1,n,1,x,0);
			}
			trh.update(1,n,1,i,1);
			trh.updh(1,n,1,lt[i],i);
		}
		for(auto x:ask[i])
		{
			if(x.id>0)ans[x.id]+=trh.getpre(x.x);
			else ans[-x.id]-=trh.getpre(x.x);
		}
	}
	for(int i=1;i<=q;i++)
	{
		writech(ans[i],'\n');
	}
	Code by MCYYDS
}
posted @ 2026-08-03 12:00  MCYYDS  阅读(1)  评论(0)    收藏  举报