【2019北京集訓3】邏輯 樹剖+2-sat
阿新 • • 發佈:2019-04-04
fin 布爾 依次 先來 邏輯 需要 lis 題目 str
題目大意:有一顆有$m$個葉子節點的二叉樹。
對於葉子節點$i$,$x[i]=(a[i]\ xor\ V_{p[i]})or(b[i]\ xor\ V_{q[i]})$
對於非葉子節點$i$,$x[i]=x[sonl]\ and\ x[sonr]$。
上文的$or$和$xor$均為邏輯運算符。且V為一個長度為$n$的布爾數組,需要你自己構造。
下面問:對於每個非葉子節點$i$,問是否存在一個序列V,使得$x[i]=true$。
數據範圍:$n,m≤2\times 10^{5}$
我們先來考慮下暴力應該怎麽做
我們直接暴力將以$i$為根的子樹內所有葉節點取出,轉換出對應的了邏輯表達式,然後根據2-sat那一套建圖,直接tarjan即可。
這麽搞,數據優秀的話(給你一個毛毛蟲圖),你就會爆炸
考慮一種不會爆炸的做法:
我們對這棵樹跑一次樹剖,我們根據鏈長依次在鏈上進行二分,查找出最接近根的,能夠構造出true的點。
然後冷靜分析一波,發現這個復雜度好像是$O(n\log^2\ n)$的,似乎問題不大。
可是問題在於這一題采用$O(n^2)$的做法可以直接艹過此題,我就並沒有去寫高級做法了qwq
1 #include<bits/stdc++.h> 2 #define M 500005 3 using namespace std; 4 5 int n,m,rt=0; 6 int p[M]={0},q[M]={0},A[M]={0},B[M]={0},in[M]={0}; 7 8 vector<int> G[M]; 9 10 void ReadData(){ 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=m;i++){ 13 int P,Q; scanf("%d%d",&P,&Q); 14 p[i]=abs(P); q[i]=abs(Q); 15 A[i]=(P<0); B[i]=(Q<0); 16 }17 for(int i=m+1;i<m*2;i++){ 18 int x,y; scanf("%d%d",&x,&y); 19 G[i].push_back(x); 20 G[i].push_back(y); 21 in[x]++; in[y]++; 22 } 23 for(int i=1;i<m*2;i++) 24 if(in[i]==0){rt=i;} 25 } 26 27 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},use=0; 28 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} 29 int dfn[M]={0},low[M]={0},b[M]={0},d[M]={0},cnt=0,t=0; stack<int> s; 30 void dfs(int x){ 31 dfn[x]=low[x]=++t; b[x]=1; s.push(x); 32 for(int i=head[x];i;i=e[i].next) 33 if(!dfn[e[i].u]) dfs(e[i].u),low[x]=min(low[x],low[e[i].u]); 34 else if(b[e[i].u]) low[x]=min(low[x],dfn[e[i].u]); 35 if(dfn[x]==low[x]){ 36 cnt++; int u; 37 do{ 38 u=s.top(); s.pop(); 39 b[u]=0; d[u]=cnt; 40 }while(u!=x); 41 } 42 } 43 44 vector<int> List; 45 void findpoint(int x){ 46 int X; 47 X=p[x]; dfn[X]=d[X]=head[X]=0; 48 X+=n; dfn[X]=d[X]=head[X]=0; 49 X=q[x]; dfn[X]=d[X]=head[X]=0; 50 X+=n; dfn[X]=d[X]=head[X]=0; 51 if(G[x].size()==0){ 52 List.push_back(x); 53 return; 54 } 55 for(int i=0;i<G[x].size();i++) 56 findpoint(G[x][i]); 57 } 58 59 bool check(int x){ 60 List.clear(); 61 use=cnt=t=0; 62 findpoint(x); 63 for(int i=0;i<List.size();i++){ 64 int v = List[i]; 65 int rtid = q[v], lftid = p[v]; 66 int lft = A[v], rt = B[v]; 67 add(rtid+rt*n,lftid+(1-lft)*n); 68 add(lftid+lft*n,rtid+(1-rt)*n); 69 } 70 for(int i=0;i<List.size();i++){ 71 int now=List[i]; 72 int u=p[now],v=q[now]; 73 if(!dfn[u]) dfs(u); 74 if(!dfn[v]) dfs(v); 75 } 76 for(int i=0;i<List.size();i++){ 77 int now=List[i]; 78 int u=p[now],v=q[now]; 79 if(d[u]==d[u+n]) return 0; 80 if(d[v]==d[v+n]) return 0; 81 } 82 return 1; 83 } 84 85 int ans[M]={0}; 86 bool solve(int x,int ok){ 87 if(G[x].size()==0) return 1; 88 if(!ok) ok=check(x); 89 if(ok) ans[x-m]=1; 90 solve(G[x][0],ok); solve(G[x][1],ok); 91 } 92 93 int main(){ 94 ReadData(); 95 solve(rt,0); 96 for(int i=1;i<m;i++) printf("%d",ans[i]); 97 }
【2019北京集訓3】邏輯 樹剖+2-sat