#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
}

浙公网安备 33010602011771号