LOJ #6036.「雅禮集訓 2017 Day4」編碼 Trie樹上2-sat

記得以前作過幾道2-sat裸體,以及幾道2-sat前綴優化建圖,這道題使用了前綴樹上前綴樹優化建圖.
咱們暴力建圖確定是n^2級別的,那麼咱們要是想讓邊數少點,就得使用一些騷操做.
咱們觀察咱們的限制條件,不就是選了一個點,那麼這個點的前綴都不能選嗎(選了一個點,以他爲前綴的的點也不能選,這個限制條件能夠經過前面那個限制條件體現出來,因此說觀察到問題本質是同樣的,能夠簡化咱們的問題).那麼咱們就能夠在Trie上建圖,使得選擇一個點,那麼他的前綴點都必須不能選,就能夠了.可是對於一個點上有多個點的狀況,咱們要特殊處理,個人處理方法是,把那些點拽出來做爲樹點.
最後說一下,要注意2-sat建圖必定要連逆否命題邊.
(感受本身2-sat好虛啊……)
語言筆記:
exit(0),只要你在程序中使用,不管在哪裏,直接正常退出,具體狀況見http://blog.csdn.net/u010046690/article/details/47105665ide

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=500010;
struct V{
  int to,next;
}c[N<<6];
int head[N<<1],t;
inline void add(int x,int y){
  c[++t].to=y,c[t].next=head[x],head[x]=t;
}
char s[N],*begin[N];
int n,len[N],m;
int pos[N],temp[N];
int dfn[N<<1],low[N<<1],belong[N<<1],stack[N<<1],top,num,Ti;
bool in[N<<1];
inline void Tarjan(int x){
  dfn[x]=low[x]=++Ti;
  stack[++top]=x;
  in[x]=true;
  register int i;
  for(i=head[x];i;i=c[i].next)
    if(!dfn[c[i].to]){
      Tarjan(c[i].to);
      low[x]=std::min(low[x],low[c[i].to]);
    }else if(in[c[i].to])
      low[x]=std::min(low[x],dfn[c[i].to]);
  if(low[x]==dfn[x]){
    ++num;
    register int j;
    do{
      j=stack[top--];
      in[j]=false;
      belong[j]=num;
    }while(j!=x);
  }
}
#define choose(a,b) (((a)<<1)-(b))
struct Trie{
  Trie *ch[2];
  std::vector<int> mem;
  Trie(){ch[0]=ch[1]=NULL,mem.clear();}
  inline void* operator new(size_t);
}*root,*C,*mempool;
inline void* Trie::operator new(size_t){
  if(C==mempool){
    C=new Trie[(1<<15)+10];
    mempool=C+(1<<15)+10;
  }
  return C++;
}
inline void build(Trie *p,int id){
  register int i,x,a,b,size=p->mem.size();
  if(!size)return;
  for(i=0;i<size;++i){
    x=p->mem[i];
    if((pos[x]==-1&&pos[id]==-1)||(pos[x]==-1&&pos[id]>=len[x])){
      puts("NO");
      exit(0);
    }
    if(pos[x]==pos[id]){
      add(choose(x,0),choose(id,1));
      add(choose(x,1),choose(id,0));
      add(choose(id,1),choose(x,0));
      add(choose(id,0),choose(x,1));
    }else{
      if(pos[id]==-1||pos[id]>=len[x]){
        if(begin[id][pos[x]]=='1'){
          add(choose(x,1),choose(x,0));
        }else{
          add(choose(x,0),choose(x,1));
        }
      }else{
        if(pos[x]==-1){
          if(begin[x][pos[id]]=='1'){
            add(choose(id,1),choose(id,0));
          }else{
            add(choose(id,0),choose(id,1));
          }
        }else{
          a=begin[id][pos[x]]=='1';
          b=begin[x][pos[id]]=='1';
          add(choose(x,a),choose(id,b^1));
          add(choose(id,b),choose(x,a^1));
        }
      }
    }
  }
}
inline void insert(int id){
  register Trie *p=root,*w;
  register int i,j,l=len[id];
  for(i=0;i<l;++i){
    if(begin[id][i]=='?'){
      if(!p->ch[0])
        p->ch[0]=new Trie();
      w=p->ch[0];
      build(w,id);
      for(j=i+1;j<l;++j){
        if(!w->ch[begin[id][j]-'0'])
          w->ch[begin[id][j]-'0']=new Trie();
        w=w->ch[begin[id][j]-'0'];
        build(w,id);
      }
      w->mem.push_back(id);
      if(!p->ch[1])
        p->ch[1]=new Trie();
      w=p->ch[1];
      build(w,id);
      for(j=i+1;j<l;++j){
        if(!w->ch[begin[id][j]-'0'])
          w->ch[begin[id][j]-'0']=new Trie();
        w=w->ch[begin[id][j]-'0'];
        build(w,id);
      }
      w->mem.push_back(id);
      return;
    }
    if(!p->ch[begin[id][i]-'0'])
      p->ch[begin[id][i]-'0']=new Trie();
    p=p->ch[begin[id][i]-'0'];
    build(p,id);
  }
  p->mem.push_back(id);
}
inline bool comp(int x,int y){
  return len[x]<len[y];
}
inline void Init(){
  root=new Trie();
  scanf("%d",&n);
  register int i,j;
  for(i=1;i<=n;++i){
    pos[i]=-1;
    begin[i]=s+m;
    scanf("%s",s+m);
    len[i]=strlen(s+m);
    m+=len[i];
    temp[i]=i;
    for(j=0;j<len[i];++j)
      if(begin[i][j]=='?'){
        pos[i]=j;
        break;
      }
  }
  std::sort(temp+1,temp+(n+1),comp);
  for(i=1;i<=n;++i){
    insert(temp[i]);
  }
}
inline bool check(){
  register int i;
  for(i=1;i<=(n<<1);++i)
    if(!dfn[i])
      Tarjan(i);
  for(i=1;i<=n;++i)
    if(belong[choose(i,1)]==belong[choose(i,0)])
      return false;
  return true;
}
int main(){
  //freopen("rio.in","r",stdin);
  Init();
  puts(check()?"YES":"NO");
  return 0;
}
88分暴力
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
const int N=500010;
struct V{int to,next;}c[N<<6];
int head[N*10],t;
inline void add(int x,int y){
  c[++t].to=y,c[t].next=head[x],head[x]=t;
}
char s[N];
int n,cnt;
int dfn[N*10],low[N*10],belong[N*10],stack[N*10],top,num,Ti;
bool in[N*10];
inline void Tarjan(int x){
  dfn[x]=low[x]=++Ti;
  stack[++top]=x;
  in[x]=true;
  R int i;
  for(i=head[x];i;i=c[i].next)
    if(!dfn[c[i].to]){
      Tarjan(c[i].to);
      low[x]=std::min(low[x],low[c[i].to]);
    }else if(in[c[i].to])
      low[x]=std::min(low[x],dfn[c[i].to]);
  if(low[x]==dfn[x]){
    ++num;
    do{
      i=stack[top--];
      in[i]=false;
      belong[i]=num;
    }while(i!=x);
  }
}
#define H(a,b) (((a)<<1)-(b))
struct Trie{
  Trie *ch[2];
  std::vector<int> mem;
  Trie(){ch[0]=ch[1]=NULL,mem.clear();}
  inline void* operator new(size_t);
}*root,*C,*mempool;
inline void* Trie::operator new(size_t){
  if(C==mempool){
    C=new Trie[(1<<15)+10];
    mempool=C+(1<<15)+10;
  }
  return C++;
}
inline void dfs(Trie *p,int fa){
  if(!p)return;
  R int i,j,x,last=fa,size=p->mem.size();
  for(i=0;i<size;++i){
    x=p->mem[i];
    ++cnt;
    if(x>0)j=1;
    else x=-x,j=0;
    add(H(x,j),H(cnt,1));
    add(H(cnt,0),H(x,j^1));
    add(H(x,j),H(last,0));
    add(H(last,1),H(x,j^1));
    add(H(cnt,0),H(last,0));
    add(H(last,1),H(cnt,1));
    last=cnt;
  }
  ++cnt;
  if(last){
    add(H(cnt,0),H(last,0));
    add(H(last,1),H(cnt,1));
  }
  last=cnt;
  dfs(p->ch[0],last);
  dfs(p->ch[1],last);
}
inline void insert(int id){
  scanf("%s",s);
  R Trie *p=root,*w;
  R int i,j,l=strlen(s);
  for(i=0;i<l;++i)s[i]-='0';
  for(i=0;i<l;++i){
    if(s[i]>1){
      w=(!p->ch[0])?p->ch[0]=new Trie():p->ch[0];
      for(j=i+1;j<l;++j)
        w=(!w->ch[s[j]])?w->ch[s[j]]=new Trie():w->ch[s[j]];
      w->mem.push_back(-id);
      w=(!p->ch[1])?p->ch[1]=new Trie():p->ch[1];
      for(j=i+1;j<l;++j)
        w=(!w->ch[s[j]])?w->ch[s[j]]=new Trie():w->ch[s[j]];
      w->mem.push_back(id);
      return;
    }
    p=(!p->ch[s[i]])?p->ch[s[i]]=new Trie():p->ch[s[i]];
  }
  add(H(id,0),H(id,1));
  p->mem.push_back(id);
}
inline bool check(){
  R int i;
  for(i=1;i<=(cnt<<1);++i)
    if(!dfn[i])Tarjan(i);
  for(i=1;i<=cnt;++i)
    if(belong[H(i,1)]==belong[H(i,0)])
      return false;
  return true;
}
int main(){
  root=new Trie();
  scanf("%d",&n),cnt=n;
  R int i;
  for(i=1;i<=n;++i)insert(i);
  dfs(root,0);
  puts(check()?"YES":"NO");
  return 0;
}
100分正解
相關文章
相關標籤/搜索