【洛谷P4319】变化的道路

题目

题目链接:https://www.luogu.com.cn/problem/P4319
小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着。
根据 H 国的道路法,H 国道路都有一个值 \(w\),表示如果小 w 和小 c 通过这条道路,那么他们的 L 值会减少 \(w\),但是如果小 w 和小 c 在之前已经经过了这条路,那么他们的 L 值不会减少。
H 国有 \(N\) 个国家,最开始 H 国有 \(n-1\) 条道路,这 \(n-1\) 条道路刚好构成一棵树。
小 w 将和小 c 从 H 国的城市 1 出发,游览 H 国的所有城市,总共游览 32766 天,对于每一天,他们都希望游览结束后 L 值还是一个正数,那么他们出发时 L 值至少为多少。
H 国的所有边都是无向边,没有一条道路连接相同的一个城市。
\(n\leq 50000\)。

思路

就是给出一棵树,再给出若干条边,且后面给的每一条边只有在时间在区间 \([l,r]\) 内时才可以走。求每一天的最小生成树 \(+1\)。
有区间的限制并不是很好搞,所以考虑离线下来。
还是没什么想法,看题解。线段树分治 + LCT。mlgb 板子题。果然太菜了。
把每一个询问覆盖到线段树的 \(O(\log 32766)\) 区间上,然后 LCT 维护最小生成树即可。回溯时 cut 一下就好了。
时间复杂度 \(O(m\log m\log n)\)。其中 \(m=32766\)。

代码

喜提最劣解。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=200010,M=32766;
int n,m,U[N],V[N];
ll ans;

struct node
{
	int x,y;
};

struct LCT
{
	#define lc ch[x][0]
	#define rc ch[x][1]
	int val[N],maxv[N],ch[N][2],fa[N];
	bool rev[N];
	
	bool pos(int x) { return x==ch[fa[x]][1]; }
	bool notrt(int x) { return x==ch[fa[x]][0] || x==ch[fa[x]][1]; }
	
	void pushup(int x)
	{
		int v1=val[x],v2=val[maxv[lc]],v3=val[maxv[rc]];
		if (v1>=v2 && v1>=v3) maxv[x]=x;
		if (lc && v2>=v1 && v2>=v3) maxv[x]=maxv[lc];
		if (rc && v3>=v1 && v3>=v2) maxv[x]=maxv[rc];
	}
	
	void pushdown(int x)
	{
		if (rev[x])
		{
			swap(ch[lc][0],ch[lc][1]); rev[lc]^=1;
			swap(ch[rc][0],ch[rc][1]); rev[rc]^=1;
			rev[x]=0;
		}
	}
		
	void rotate(int x)
	{
		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
		pushup(y); pushup(x);
	}
	
	void splay(int x)
	{
		stack<int> st; st.push(x);
		for (int i=x;notrt(i);i=fa[i]) st.push(fa[i]);
		for (;st.size();st.pop()) pushdown(st.top());
		for (;notrt(x);rotate(x))
		{
			int y=fa[x];
			if (notrt(y)) rotate(pos(x)==pos(y)?y:x);
		}
	}
	
	void access(int x)
	{
		for (int y=0;x;y=x,x=fa[x])
		{
			splay(x); ch[x][1]=y;
			pushup(x);
		}
	}
	
	void makert(int x)
	{
		access(x); splay(x);
		swap(lc,rc); rev[x]^=1;
	}
	
	void link(int x,int y)
	{
		makert(x); access(y); splay(y);
		fa[x]=y; access(x);
	}
	
	void cut(int x,int y)
	{
		makert(x); access(y); splay(x);
		ch[x][1]=fa[y]=0;
		pushup(x);
	}
	#undef lc
	#undef rc
}lct;

struct SegTree
{
	vector<node> e[N];
	stack<node> st;
	
	void update(int x,int l,int r,int ql,int qr,node v)
	{
		if (ql<=l && qr>=r)
			return (void)e[x].push_back(v);
		int mid=(l+r)>>1;
		if (ql<=mid) update(x*2,l,mid,ql,qr,v);
		if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
	}
	
	void query(int x,int l,int r)
	{
		int cnt=st.size();
		for (int i=0;i<e[x].size();i++)
		{
			int w=e[x][i].x,id=e[x][i].y;
			lct.makert(U[id]); lct.access(V[id]); lct.splay(V[id]);
			if (lct.val[lct.maxv[V[id]]]>w)
			{
				int y=lct.maxv[V[id]];
				ans=ans-lct.val[y]+w;
				lct.cut(y,U[y]); lct.cut(y,V[y]);
				lct.link(id,U[id]); lct.link(id,V[id]);
				st.push((node){y,id});
			}
		}
		if (l==r) cout<<ans+1<<"\n";
		else
		{
			int mid=(l+r)>>1;
			query(x*2,l,mid); query(x*2+1,mid+1,r);
		}
		for (;st.size()>cnt;st.pop())
		{
			int id1=st.top().x,id2=st.top().y;
			ans=ans-lct.val[id2]+lct.val[id1];
			lct.cut(id2,U[id2]); lct.cut(id2,V[id2]);
			lct.link(id1,U[id1]); lct.link(id1,V[id1]);
		}
	}
}seg;

int main()
{
	scanf("%d",&n);
	for (int i=1;i<N;i++) lct.maxv[i]=i;
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&lct.val[i+n]);
		lct.link(x,i+n); lct.link(y,i+n);
		ans+=lct.val[i+n];
		U[i+n]=x; V[i+n]=y;
	}
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		int u,v,l,r,w;
		scanf("%d%d%d%d%d",&u,&v,&w,&l,&r);
		lct.val[n*2+i]=w; U[n*2+i]=u; V[n*2+i]=v;
		seg.update(1,1,M,l,r,(node){w,n*2+i});
	}
	seg.query(1,1,M);
	return 0;
}
上一篇:洛谷 P3721 - [AH2017/HNOI2017]单旋(LCT)


下一篇:[HNOI2010]弹飞绵羊