san - 主席树优化建图 - 强连通分量

题目大意:每一个人有三个属性(ai,bi,ci),定义一个人比另一个大当且仅当有至少两维更大。保证a,b,c分别是三个排列。执行以下代码:

//p is a permutation of [1,n]
int ans=p[1];
for(int i=2;i<=n;i++)
	if(person[p[i]]>person[ans]) ans=p[i];
return ans;

问有多少人,使得存在至少一个排列,使得他是ans。
n ≤ 1 0 5 n\le10^5 n105
题解:
建图,这是个竞赛图,缩点,这是条链,显然不在链上第一坨点的人不会是答案,而由于强连通的竞赛图存在哈密顿回路,因此在第一坨点上的人一定有可能成为答案,因此用主席树优化建图跑tarjan即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=100010;
struct A{
    int a,b,c;A(int _a=0,int _b=0,int _c=0) { a=_a,b=_b,c=_c; }
    inline int input() { return a=inn(),b=inn(),c=inn(); }
    inline bool operator<(const A &n)const { return int(a>n.a)+int(b>n.b)+int(c>n.c)<=1; }
    inline bool operator>(const A &n)const { return int(a>n.a)+int(b>n.b)+int(c>n.c)>=2; }
    inline int show()const { return debug(a)sp,debug(b)sp,debug(c)ln,0; }
}a[N];
namespace subtask1{
    const int N=20;int p[N],ans[N];
    inline int brute_force_20(int n)
    {
        rep(i,1,n) p[i]=i,ans[i]=0;
        do{
            int t=p[1];
            rep(i,2,n) if(a[p[i]]>a[t]) t=p[i];
            ans[t]=1;
        }while(next_permutation(p+1,p+n+1));
        rep(i,1,n) printf("%d\n",ans[i]);return 0;
    }
}
namespace subtask23{
    const int N=2010,M=N*N/2;
    struct edges{
        int to,pre;
    }e[M];int h[N],etop,vis[N],dfn[N],low[N],dfc,cc,bel[N],ind[N];stack<int> s;
    inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
    int tarjan(int x)
    {
        vis[x]=1,dfn[x]=low[x]=++dfc,s.push(x);
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]) tarjan(y),low[x]=min(low[x],low[y]);
            else if(vis[y]==1) low[x]=min(low[x],dfn[y]);
        if(low[x]==dfn[x])
        {
            bel[x]=++cc,vis[x]=2;
            for(int y=s.top();y^x;y=s.top())
                bel[y]=cc,vis[y]=2,s.pop();s.pop();
        }
        return 0;
    }
    inline int brute_force_60(int n)
    {
        memset(vis,0,sizeof(int)*(n+1));
        memset(ind,0,sizeof(int)*(n+1));
        rep(i,1,n) rep(j,i+1,n)
            if(a[i]>a[j]) add_edge(i,j);
            else add_edge(j,i);
        dfc=0,cc=0;
        rep(i,1,n) if(!vis[i]) tarjan(i);
        rep(x,1,n) for(int i=h[x],y;i;i=e[i].pre)
            if(bel[x]^bel[y=e[i].to]) ind[bel[y]]++;
        rep(i,1,n) printf("%d\n",int(ind[bel[i]]==0));
        return 0;
    }
}
namespace subtask4{
    const int NC=6100000,M=14000000,N=100010;
    struct edges{
        int to,pre;
    }e[M];stack<int> s;
    int h[NC],etop,vis[NC],dfn[NC],low[NC],dfc,cc,bel[NC],ind[NC],hs[NC],isr[NC];
    inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
    int tarjan(int x)
    {
        vis[x]=1,dfn[x]=low[x]=++dfc,s.push(x);
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]) tarjan(y),low[x]=min(low[x],low[y]);
            else if(vis[y]==1) low[x]=min(low[x],dfn[y]);
        if(low[x]==dfn[x])
        {
            bel[x]=++cc,vis[x]=2;
            for(int y=s.top();y^x;y=s.top())
                bel[y]=cc,vis[y]=2,s.pop(),hs[cc]|=isr[y];
            s.pop(),hs[cc]|=isr[x];
        }
        return 0;
    }
    int lc[NC],rc[NC],node_cnt,v[N],x[N],y[N];
    inline int new_node() { return node_cnt++,lc[node_cnt]=rc[node_cnt]=0,node_cnt; }
    int build(int &x,int l,int r)
    {
        x=new_node();if(l==r) return 0;int mid=(l+r)>>1;
        build(lc[x],l,mid),build(rc[x],mid+1,r);
        return add_edge(x,lc[x]),add_edge(x,rc[x]);
    }
    inline int AddEdge(int x,int l,int r,int s,int t,int p)
    {
        if(s<=l&&r<=t) return add_edge(p,x);int mid=(l+r)>>1;
        if(s<=mid) AddEdge(lc[x],l,mid,s,t,p);
        if(mid<t) AddEdge(rc[x],mid+1,r,s,t,p);
        return 0;
    }
    inline int update(int &x,int y,int l,int r,int p,int v)
    {
        x=new_node(),lc[x]=lc[y],rc[x]=rc[y];
        if(l==r) return add_edge(x,v);int mid=(l+r)>>1;
        if(p<=mid) update(lc[x],lc[y],l,mid,p,v);
        if(mid<p) update(rc[x],rc[y],mid+1,r,p,v);
        return add_edge(x,lc[x]),add_edge(x,rc[x]);
    }
    inline int prelude(int n)
    {
        int rt,tmp;build(rt,1,n);
        rep(i,1,n) v[x[i]]=i;
        rep(i,1,n)
            AddEdge(rt,1,n,1,y[v[i]],v[i]),
            update(tmp,rt,1,n,y[v[i]],v[i]),rt=tmp;
        return 0;
    }
    queue<int> q;vector<int> g[NC];int fr[NC];
    inline int toposort()
    {
        rep(i,1,cc) if(!ind[i]) q.push(i);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            Rep(i,g[x])
            {
                int y=g[x][i];
                ind[y]--,fr[y]|=fr[x]|hs[x];
                if(!ind[y]) q.push(y);
            }
        }
        return 0;
    }
    inline int acceptable_solution(int n)
    {
        node_cnt=n;rep(i,1,n) isr[i]=1;
        rep(i,1,n) x[i]=a[i].a,y[i]=a[i].b;prelude(n);
        rep(i,1,n) x[i]=a[i].a,y[i]=a[i].c;prelude(n);
        rep(i,1,n) x[i]=a[i].b,y[i]=a[i].c;prelude(n);
        rep(i,1,node_cnt) if(!vis[i]) tarjan(i);
        rep(x,1,node_cnt) for(int i=h[x],y;i;i=e[i].pre)
            if(bel[x]^bel[y=e[i].to]) g[bel[x]].pb(bel[y]),ind[bel[y]]++;
        toposort();
        rep(i,1,n) printf("%d\n",fr[bel[i]]==0);return 0;
    }
}
#define LSH(x) rep(i,1,n) val[i]=a[i].x;sort(val+1,val+n+1);rep(i,1,n) a[i].x=lower_bound(val+1,val+n+1,a[i].x)-val
int val[N];
int main()
{
    int n=inn();rep(i,1,n) a[i].input();
    LSH(a);LSH(b);LSH(c);
    if(n<=10) return subtask1::brute_force_20(n);
    if(n<=2000) return subtask23::brute_force_60(n);
    return subtask4::acceptable_solution(n);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值