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/47105665
#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; }
#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; }
苟利国家生死以, 岂因祸福避趋之。