P3500【2015多校联训6】独立集(dp)

来源:互联网 发布:linux内核设计艺术pdf 编辑:程序博客网 时间:2024/06/03 17:54

题目大意: 求一数列的最大上升子序列+必定存在此最大上升子序列的点

题解

如果一个点必定存在与最长上升子序列中,那么必须满足两个条件:1.该点存在于最长上升子序列中。2.通过此点的最长上升子序列长度唯一。

但此题由于数据范围为1000005,所以常规n方求最长上升子序列的方法肯定不行,那么就考虑用树状数组维护小于当前值的最大上升子序列数即可。

如何判断一个点是否在最长上升子序列中?从前后各扫一遍如果前后的最长上升子序列想加的值等于最长上升自序列长度,那么该点一定在最长上升子序列中。

代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;#define maxn 50005#define maxn1 200005#define ll long longconst long long inf=100000000000000LL;int n,m;int cnt,cnt1;int St[maxn1],End[maxn1],Next[maxn1],Last[maxn1],Len[maxn1];int End1[maxn1],Next1[maxn1],Last1[maxn1],Len1[maxn1];int End2[maxn1],Next2[maxn1],Last2[maxn1];ll dis[maxn][5];priority_queue<pair<ll,ll> >q;bool mark[maxn];int a,b,c,d;void dj(int x,int y){    int i,j;    memset(mark,false,sizeof(mark));    for(i=1;i<=n;i++) dis[i][y]=inf;    dis[x][y]=0;    q.push(make_pair(0,x));    while(q.size()){        int t,s;        t=q.top().second;        s=-q.top().first;        q.pop();        if(mark[t]) continue;        mark[t]=true;        for(i=Last[t];i;i=Next[i]){            int en=End[i];            if(dis[en][y]>s+Len[i]){                dis[en][y]=s+Len[i];                q.push(make_pair(-dis[en][y],en));              }        }    }}void dj2(int x,int y){    int i,j;    memset(mark,false,sizeof(mark));    for(i=1;i<=n;i++) dis[i][y]=inf;    dis[x][y]=0;    q.push(make_pair(0,x));    while(q.size()){        int t,s;        t=q.top().second;        s=-q.top().first;        q.pop();        if(mark[t]) continue;        mark[t]=true;        for(i=Last1[t];i;i=Next1[i]){            int en=End1[i];            if(dis[en][y]>s+Len1[i]){                dis[en][y]=s+Len1[i];                q.push(make_pair(-dis[en][y],en));            }        }    }}void insert(int x,int y,int z){      Next[++cnt]=Last[x];      Last[x]=cnt;      End[cnt]=y;      Len[cnt]=z;      St[cnt]=x;}void insert1(int x,int y,int z){    Next1[cnt]=Last1[x];    Last1[x]=cnt;    End1[cnt]=y;    Len1[cnt]=z;}void insert2(int x,int y){    Next2[++cnt1]=Last2[x];    Last2[x]=cnt1;    End2[cnt1]=y;}ll minl;int ru[maxn];bool jd[maxn],mark2[maxn];int ans=0;queue<int>tp;int dp[maxn];main(){//  freopen("game.in","r",stdin);//  freopen("game.out","w",stdout);    int i,j;    scanf("%d%d",&n,&m);    for(i=1;i<=m;i++){        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        insert(x,y,z);        insert1(y,x,z);     }    scanf("%d%d%d%d",&a,&b,&c,&d);    dj(a,1);dj(c,3);    dj2(b,2);dj2(d,4);    int minl=dis[b][1]+dis[d][3];    int minl1=dis[b][1],minl2=dis[d][3];    if(minl>=inf){        cout<<"-1";return 0;    }    for(i=1;i<=n;i++){        if(dis[i][1]+dis[i][2]+dis[i][3]+dis[i][4]==minl){            jd[i]=true;        }    }    for(i=1;i<=n;i++)    for(i=1;i<=m;i++){        int x=St[i],y=End[i];        if(dis[x][1]+dis[x][3]+Len[i]*2+dis[y][2]+dis[y][4]==minl){            insert2(x,y);            ru[y]++;        }    } //建立新图 //  for(i=1;i<=n;i++)cout<<chu[i];    for(i=1;i<=n;i++){        if(ru[i]==0){            tp.push(i);            if(jd[i]) dp[i]=1;        }    }    while(tp.size()){        int t=tp.front();        tp.pop();        for(i=Last2[t];i;i=Next2[i]){            int en=End2[i];             dp[en]=max(dp[en],dp[t]+1);            ru[en]--;            if(ru[en]==0) tp.push(en);        }           }    for(i=1;i<=n;i++) ans=max(ans,dp[i]);    cout<<ans;}
原创粉丝点击