[线段树 & 前缀 优化建图 二分 2-SAT] CF Gym100159 facebook-hacker-cup-2012 I. Unfriending

来源:互联网 发布:唐狮质量怎么样 知乎 编辑:程序博客网 时间:2024/06/05 10:08

二分答案

对于一个点,肯定有一个区间里的点和它不能共存

这个可以用线段树优化建图,每个friend list最多只能删一个,用前缀优化建图

还要一些针对随机数据什么的trick才能过…比如二分中的那个特判

#include <cstdio>#include <iostream>#include <algorithm>#include <vector>#include <cstring>using namespace std;const int N=5000010;int T,n,m,cnt,tot;int G[N],vis[N],dfn[N],low[N],s[N],g[N],vst[N],ig,tp,it,imax;struct edge{    int t,nx;}E[N<<1];pair<int,int> a[N];inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void rea(int &x){    char c=nc(); x=0;    for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());}vector<pair<int,int> > b[N];inline void addedge(int x,int y){    //cout<<x<<' '<<y<<endl;    E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;}void Build(int g,int l,int r){    if(l==r) return imax=max(imax,g),addedge(tot+g,a[l].second<<1|1);    int mid=l+r>>1;    Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);    addedge(tot+g,tot+(g<<1)); addedge(tot+g,tot+(g<<1|1));}void link(int g,int L,int R,int l,int r,int x){    if(L==l && r==R) return addedge(x,tot+g);    int mid=L+R>>1;    if(r<=mid) link(g<<1,L,mid,l,r,x);    else if(l>mid) link(g<<1|1,mid+1,R,l,r,x);    else link(g<<1,L,mid,l,mid,x),link(g<<1|1,mid+1,R,mid+1,r,x);}void tarjan(int x){    dfn[x]=low[x]=++it; vis[x]=1; s[++tp]=x;    for(int i=G[x];i;i=E[i].nx){        if(!vis[E[i].t]) tarjan(E[i].t);        if(vis[E[i].t]!=2) low[x]=min(low[x],low[E[i].t]);    }    if(dfn[x]==low[x]){        int k; ++ig;        do{ k=s[tp--]; vis[k]=2; g[k]=ig; }while(k!=x && tp);    }}inline bool check(int x){    memset(G,0,sizeof(G));    memset(vis,0,sizeof(vis));    cnt=tp=ig=it=imax=0; tot=(n-1<<1|1)+1;    Build(1,0,n-1);    int cc=0;    for(int i=0;i<n;i++)        if(!vst[i]) addedge(i<<1|1,i<<1);    for(int i=0,j=0;i<n;i++){        while(a[i].first-a[j].first>=x) j++;        if(j<i) link(1,0,n-1,j,i-1,a[i].second<<1),cc+=i-j;    }    if(cc>=1200000) return false;    for(int i=n-1,j=n-1;~i;i--){        while(a[j].first-a[i].first>=x) j--;        if(j>i) link(1,0,n-1,i+1,j,a[i].second<<1);    }    tot+=imax+1;    for(int i=1;i<=m;i++){        addedge(b[i][0].second<<1|1,tot);        addedge(tot+1,b[i][0].second<<1);        for(int j=1;j<b[i].size();j++){            addedge(tot+(j-1<<1),tot+(j<<1));            addedge(tot+(j<<1|1),tot+(j-1<<1|1));            addedge(b[i][j].second<<1|1,tot+(j<<1));            addedge(tot+(j<<1|1),b[i][j].second<<1);            addedge(b[i][j].second<<1|1,tot+(j-1<<1|1));            addedge(tot+(j-1<<1),b[i][j].second<<1);        }        tot+=(b[i].size()<<1|1)+1;    }    for(int i=0;i<=tot;i++)        if(!vis[i]) tarjan(i);    for(int i=0;i<n;i++)        if(g[i<<1]==g[i<<1|1]) return false;    return true;}int main(){    rea(T); int CASE=0;    while(T--){        memset(vst,0,sizeof(vst));        rea(n); rea(m); rea(a[0].first);        int x,y,p; rea(x); rea(y); rea(p);        for(int i=1;i<n;i++)             a[i].first=(1LL*a[i-1].first*x+y)%p;        for(int i=0;i<n;i++)             a[i].second=i;        for(int i=1;i<=m;i++){            int size,x,y; rea(size);            b[i].resize(size);            rea(b[i][0].second); rea(x); rea(y);            b[i][0].second%=n;            for(int j=1;j<size;j++)                 b[i][j].second=(1LL*b[i][j-1].second*x+y)%n;            for(int j=0;j<size;j++)                 b[i][j].first=a[b[i][j].second].first,vst[b[i][j].second]=1;            sort(b[i].begin(),b[i].end());            b[i].resize(unique(b[i].begin(),b[i].end())-b[i].begin());        }        sort(a,a+n);        int l=0,r=1e9,mid,ans=-1;        while(l<=r){            mid=l+r>>1;            if(l<10 && r>10) mid=10;            check(mid)?l=(ans=mid)+1:r=mid-1;        }        printf("Case #%d: %d\n",++CASE,ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击