zoukankan      html  css  js  c++  java
  • 【2019北京集训3】逻辑 树剖+2-sat

    题目大意:有一颗有$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 imes 10^{5}$

    我们先来考虑下暴力应该怎么做

    我们直接暴力将以$i$为根的子树内所有叶节点取出,转换出对应的了逻辑表达式,然后根据2-sat那一套建图,直接tarjan即可。

    这么搞,数据优秀的话(给你一个毛毛虫图),你就会爆炸

    考虑一种不会爆炸的做法:

    我们对这棵树跑一次树剖,我们根据链长依次在链上进行二分,查找出最接近根的,能够构造出true的点。

    然后冷静分析一波,发现这个复杂度好像是$O(nlog^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 }
  • 相关阅读:
    2.MYSQL之初体验
    nginx+uWSGI+django+virtualenv+supervisor
    静态动态网页
    web server 基础知识
    nginx与location语法详解
    编译安装nginx
    虚拟环境之virtualenvwrapper
    python开发之virtualenv
    【剑指Offer】面试题12. 矩阵中的路径
    【剑指Offer】面试题11. 旋转数组的最小数字
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10657045.html
Copyright © 2011-2022 走看看