题目
n(n<=1e5)个点,m(m<=1e5)条有向边的图,
有可能有重边自环,或图本身不连通,
依次输入m条边的u,v,w(第i条输入的边的路径号是i),
要求构造一条最长路径,使得这条路径中的路径号递增,且w是严格递增的
思路来源
https://blog.csdn.net/qq_39809664/article/details/79871282(map+BIT)
https://blog.csdn.net/white_elephant/article/details/80879562(线段树优化建图/主席树)
题解
这题做法很多,BB一个简易版本的主席树做法
自己手推一下,发现每个点都得开一棵线段树,当前u和上一个v接上
线段树应该维护两个值(w,num),对于当前W,要找到w
所以,动态开点线段树,就满足了空间要求
(*)如果map+BIT,就是用map实现动态开点
(**)线段树优化建图还不会,咕了
代码
#include
using namespace std;
const int N=1e5+10;
int n,m,root[N],cnt;
int ans,u,v,w,num;
//主席树动态开点思想
struct node
{
int l,r,mx;
node():l(0),r(0),mx(0){}
}e[N*20];
void upd(int &p,int l,int r,int x,int v)
{
if(!p)p=++cnt;
if(l==r)
{
e[p].mx=max(e[p].mx,v);
return;
}
int mid=(l+r)/2;
if(x<=mid)upd(e[p].l,l,mid,x,v);
else upd(e[p].r,mid+1,r,x,v);
e[p].mx=max(e[e[p].l].mx,e[e[p].r].mx);
}
int ask(int p,int l,int r,int ql,int qr)
{
if(ql>qr)return 0;
if(ql<=l&&r<=qr)return e[p].mx;
int mid=(l+r)/2,ans=0;
if(ql<=mid)ans=max(ans,ask(e[p].l,l,mid,ql,qr));
if(qr>mid)ans=max(ans,ask(e[p].r,mid+1,r,ql,qr));
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&u,&v,&w);
num=ask(root[u],0,1e5,0,w-1);
upd(root[v],0,1e5,w,num+1);
ans=max(ans,num+1);
}
printf("%d\n",ans);
return 0;
}