1. 程式人生 > >[線段樹 & 字首 優化建圖 二分 2-SAT] CF Gym100159 facebook-hacker-cup-2012 I. Unfriending

[線段樹 & 字首 優化建圖 二分 2-SAT] CF Gym100159 facebook-hacker-cup-2012 I. Unfriending

二分答案

對於一個點,肯定有一個區間裡的點和它不能共存

這個可以用線段樹優化建圖,每個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; }