#14120. 路径选择 题解

题目链接:#14120. 路径选择

先考虑 DAG,显然可以 dp 出来往每条边走有多少种可能,然后就可以求出往当前方向走 $ k $ 需要在哪个区间内,以及往这个方向走 $ k $ 会减多少,暴力跳是 $ O(nq) $ 的,考虑类似重链剖分的思想,每个点连一条出去的重链指向大小最大的儿子,可以在链上面二分在链上走多远,然后显然轻重链切换的次数只有 $ O(logn) $ 次,复杂度是 $ O(nlog^2n) $ 的。

对于一般图,事实上每条路径至多只会在一个环上面绕一周或以上,轻重链剖分环的路径数记为无限,找到这个环,计算绕一周需要 $ k $ 至少为多少会减多少,进行一个类型模的操作,最后按照 DAG 的方法做即可。复杂度 $ O(nlog^2n) $。

代码:

#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 0x3f3f3f3f3f3f3f3fll
#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,m,q;
pii getj(pii x,pii y)
{
	return {max(x.first,y.first),min(x.second,y.second)};
}
bool check(pii p,int x)
{
	return (p.first<=x&&x<=p.second);
}
struct BIT{
	vector<int> tree;
	void init(int x)
	{
		tree.resize(x+1);
	}
	int lowbit(int x)
	{
		return x&(-x);
	}
	int ask(int x)
	{
		int ret=0;
		for(;x;x-=lowbit(x))
		{
			ret+=tree[x];
		}
		return ret;
	}
	void upd(int x,int v)
	{
		for(;x<=n;x+=lowbit(x))
		{
			tree[x]+=v;
		}
	}
	void add(int l,int r,int v)
	{
		upd(l,v);
		upd(r+1,-v);
	}
}tree;
struct node{
	int v,p,w,s;
	bool operator<(const node &x)const{
		return p<x.p;
	}
}; 
vector<int> re[100005],tr[100005];
vector<node> e[100005];
int f[100005],in[100005],d[100005],sonv[100005];
int fa[21][100005],son[100005],sonp[100005];
pii qj[21][100005];
int dfn[100005],sz[100005],tot;
int vis[100005],cid;
bool flag[100005];
int eu[1000005],ep[1000005];
void topo()
{
	queue<int> qu;
	for(int i=1;i<=n;i++)
	{
		if(!in[i])qu.push(i);
	}
	while(qu.size())
	{
		int u=qu.front();
		qu.pop();
		f[u]=min(f[u]+1,INF);
		for(auto v:re[u])
		{
			f[v]=min(f[v]+f[u],INF);
			in[v]--;
			if(!in[v])qu.push(v);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(in[i])f[i]=INF;
	}
}
void getcyc(int u)
{
	if(!u)return ;
	if(vis[u])
	{
		if(vis[u]==cid)flag[u]=1;
		return ;
	}
	vis[u]=cid;
	getcyc(son[u]);
}
void dfs(int u)
{
	dfn[u]=++tot;
	sz[u]=1;
	qj[0][u].first-=d[u];
	qj[0][u].second-=d[u];
	for(int i=1;i<18;i++)
	{
		fa[i][u]=fa[i-1][fa[i-1][u]];
		qj[i][u]=getj(qj[i-1][u],qj[i-1][fa[i-1][u]]);
	}
	for(auto v:tr[u])
	{
		d[v]=d[u]+qj[0][v].first;
		dfs(v);
		sz[u]+=sz[v];
	}
}
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	n=read(),m=read(),q=read();
	tree.init(n);
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read(),p=read(),w=read();
		re[v].pb(u);
		in[u]++;
		e[u].pb({v,p,w,0});
		eu[i]=u;
		ep[i]=p;
	}
	topo();
	for(int i=1;i<=n;i++)
	{
		sort(e[i].begin(),e[i].end());
		int cur=0,mx=0,id=0,p=0,w=0;
		for(auto &v:e[i])
		{
			v.s=cur;
			if(!id||f[v.v]>f[id])
			{
				mx=cur;
				id=v.v;
				w=v.w;
				p=v.p;
			}
			cur=min(cur+f[v.v],INF);
		}
		if(id)
		{
			son[i]=id;
			sonp[i]=p;
			sonv[i]=w;
			qj[0][i]={mx+1,mx+f[id]};
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			++cid;
			getcyc(i);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(son[i]&&!flag[i])
		{
			fa[0][i]=son[i];
			tr[son[i]].pb(i);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(!fa[0][i])dfs(i);
	}
	for(int i=1;i<=n;i++)
	{
		if(!flag[i])tree.add(dfn[i],dfn[i]+sz[i]-1,sonv[i]);
	}
	while(q--)
	{
		int op=read();
		if(op==1)
		{
			int u=read(),k=read();
			if(f[u]<k)
			{
				puts("-1");
				continue;
			}
			k--;
			int ans=0;
			while(k)
			{
				int v=u;
				for(int i=17;i>=0;i--)
				{
					if(fa[i][v]&&check(qj[i][v],k-d[u]))v=fa[i][v];
				}
				k-=d[u]-d[v];
				ans+=tree.ask(dfn[u])-tree.ask(dfn[v]);
				if(!k)break;
				u=v;
				if(flag[u])
				{
					int len=d[son[u]]+qj[0][u].first;
					ans+=max(0ll,k/len-1)*(tree.ask(dfn[son[u]])+sonv[u]);
					k-=max(0ll,k/len-1)*len;
					if(k>=qj[0][u].first)
					{
						k-=qj[0][u].first;
						ans+=sonv[u];
						u=son[u];
					}
					if(!k)break;
				}
				int l=0,r=e[u].size()-1,ret=0;
				while(l<=r)
				{
					int mid=l+r>>1;
					if(e[u][mid].s<k)ret=mid,l=mid+1;
					else r=mid-1;
				}
				k-=e[u][ret].s+1;
				ans+=e[u][ret].w;
				u=e[u][ret].v;
			}
			writech(ans,'\n');
		}
		else
		{
			int id=read(),w=read();
			int u=eu[id];
			int pos=lower_bound(e[u].begin(),e[u].end(),(node){0,ep[id],0,0})-e[u].begin();
			if(e[u][pos].p==sonp[u])
			{
				if(flag[u])sonv[u]=w;
				else tree.add(dfn[u],dfn[u]+sz[u]-1,w-e[u][pos].w);
			}
			e[u][pos].w=w;
		}
	}
	Code by MCYYDS
}

posted @ 2026-08-03 22:05  MCYYDS  阅读(2)  评论(0)    收藏  举报