5.4

考中:

t1看了一眼,感觉像淀粉质,思考了一下,发现可以,而且代码难度也不高,在继续看和写代码之间选择了写代码,然后,果不其然,我又双叒叕想了个假算法,心塞,看了看暴力,只会30分,开始写30分的,写完以后,又思考了一下原来的错误做法,发现其实没错,又看了一眼题面,然后,果不其然,我又双叒叕看错题了,呵呵,于是看t2,很好,有30分,然后看t3,有60分,算了算,有110分,感觉还行,代码都还好,于是找看了一圈,发现没有老师,找zyz商量了一下,于是回寝室了

t1:

10分,直接枚举

30分,直接dfs一下,上组合数

剩下的待填

t2:

60分:直接做(应该没有人不会吧,我就不会)

截止时间 i 的答案ans 应当是满足 j*k >= 截止时间在 k 及以前的订单数量 k=1,2,……i  的最小的 j 

100分:待填

t3:

50分:bitset搞一下就完了

100分:

考虑50分的瓶颈,在于无法直接根据某些东西快速求出后面的点集,考虑拓扑的过程。

所以我们考虑dfs序,显然是后序,容易发现:所以x可以走到的点其实是dfs后序在x前面的点,但这样我们会发现有不合法的点,不合法的点是dfs v 结束后,dfs 接下来的v得到的,所以翻转一下从x连出去的点,dfs后序同时<=x的点就可以刚好被加入答案了

给的题解实际上更复杂了

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=300005,M=400000+5;
struct er{
    int x,y,v;
}dian[N];
struct qw{
    int x,v;
};
int cmp(qw l,qw r)
{
    return l.v<r.v;
}
vector<qw> next1[N];
int ru_1[N],ru_2[N];
void lian(int x,int y,int v)
{
    next1[x].push_back((qw){y,v});
    ru_1[y]++;
    ru_2[y]++;
}
int dfn1[N],dfn2[N],tim;
int rnk[N];
void dfs_1(int x)
{
    tim++;
    rnk[tim]=x;
    for(int i=0;i<next1[x].size();i++)
    {
        int v=next1[x][i].x;
        ru_1[v]--;
        if(!ru_1[v]) dfs_1(v);
    }
}
void dfs_2(int x)
{
    tim++;
    rnk[tim]=x;
    for(int i=0;i<next1[x].size();i++)
    {
        int v=next1[x][i].x;
        ru_2[v]--;
        if(!ru_2[v]) dfs_2(v);
    }
}
int c[N],n;
void add(int x,int v)
{
    if(x==0) return;
    while(x<=n)
    {
        c[x]+=v;
        x+=x&-x;
    }
}
int query(int x)
{
    int res=0;
    while(x)
    {
        res+=c[x];
        x-=x&-x;
    }
    return res;
}
int ans[N],f[N];
int main()
{
    freopen("souvenir.in","r",stdin);
    freopen("souvenir.out","w",stdout);
    int m;
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=n;i++)
    scanf("%d %d %d",&dian[i].x,&dian[i].y,&dian[i].v);
    while(m--)
    {
        scanf("%d %d",&x,&y);
        if(dian[y].x>dian[x].x||dian[y].y>dian[x].y) lian(x,y,dian[y].x>dian[x].x);
        else lian(y,x,dian[x].x>dian[y].x);
    }
//    for(int i=1;i<=n;i++) sort(next1[i].begin(),next1[i].end(),cmp);
    dfs_1(1);
    for(int i=1;i<=n;i++) dfn1[rnk[i]]=n-i+1;
    tim=0;
    for(int i=1;i<=n;i++) reverse(next1[i].begin(),next1[i].end());
    dfs_2(1);
    for(int i=1;i<=n;i++) dfn2[rnk[i]]=n-i+1;//图的拓扑序,不能直接dfs后面加tim++,应该等x的y全部遍历完才能把x丢进去 
    for(int i=n;i>=1;i--)
    {
        x=rnk[i];
        add(f[dian[x].v],-1);
        if(!f[dian[x].v]) f[dian[x].v]=dfn1[x];
        else f[dian[x].v]=min(f[dian[x].v],dfn1[x]);
        add(f[dian[x].v],1);
        ans[x]=query(dfn1[x]);//不能这里-1,ans+1,因为query统计的是颜色,而-1以后有的点会统计到自己的颜色,有的点不会 
    }
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}
/*
7 7
1 1 1
3 1 2
1 2 1
2 2 3
3 3 4
2 4 1
3 4 2
1 2
1 3
4 3
5 2
5 7
4 6
7 6
*/
原文地址:https://www.cnblogs.com/xsm098/p/14730318.html