[CF960F]Pathwalks

题目大意:给你一张$n$个点$m$条边的带权有向图,可能有重边和自环。边会按照顺序给出。让你求出一条最长的路径,使得路径上的边满足边权和出现的时间严格递增。路径可以重复经过同一个点。

想办法把它转化成序列上的最长上升序列

我们如果按顺序加边,那么边做边求是符合边的出现时间递增的要求的

所以当给你一条边$a$->$b$边权为$c$时,我们要在合理的复杂度内查到到$a$点边权小于$c$的最长上升序列

然后用它去更新答案和到$b$边权小于等于$c$的最大值

这显然是个线段树,然后我们再搞个动态开点,完事

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 500010
 5 #define ls ch[node][0]
 6 #define rs ch[node][1]
 7 using namespace std;
 8 int read()
 9 {
10     char ch=getchar();int x=0;
11     while(ch>'9'||ch<'0') ch=getchar();
12     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
13     return x;
14 }
15 int n,m,cnt,ans;
16 int root[M],val[M<<2],ch[M<<2][2];
17 void insert(int &node,int l,int r,int k,int x)
18 {
19     if(!node) node=++cnt;
20     val[node]=max(val[node],x);
21     if(l==r) return;
22     int mid=(l+r)/2;
23     if(k<=mid) insert(ls,l,mid,k,x);
24     else insert(rs,mid+1,r,k,x);
25 }
26 int query(int node,int l,int r,int l1,int r1)
27 {
28     if(!node) return 0;
29     if(l1>r||r1<l) return 0;
30     if(l1<=l&&r1>=r) return val[node];
31     int mid=(l+r)/2;
32     return max(query(ls,l,mid,l1,r1),query(rs,mid+1,r,l1,r1));
33 }
34 int main()
35 {
36     n=read();m=read();
37     for(int i=1;i<=m;i++)
38     {
39         int a=read(),b=read(),z=read()+1;
40         int x=query(root[a],1,100000,1,z-1)+1;
41         ans=max(ans,x);
42         insert(root[b],1,100001,z,x);
43     }
44     printf("%d",ans);
45     return 0;
46 }

猜你喜欢

转载自www.cnblogs.com/Slrslr/p/9694766.html
今日推荐