zoukankan      html  css  js  c++  java
  • LibreOJ

    题目链接

    很明显的2SAT问题,和树上距离有关显然要考虑树分治。由于2-SAT不具有容斥性,点分治不方便处理,不过我们可以边分治。

    边分治,分治过程中对每条边t左右两侧各建立一棵线段树,线段树上每个区间结点u(设代表的区间范围为[l,r])开两个条件结点p[u][0]和p[u][1],分别代表”边t该侧管辖范围内与t的该侧端点距离在[l,r]之间的点是否全不接入/全都接入“,每个结点和它的两个儿子建立约束条件p[u][0]->p[l(u)][0],p[u][0]->p[r(u)][0],p[u][1]->p[l(u)][1],p[u][1]->p[r(u)][1]。对于边t管辖范围内的每个结点x(设x代表接入了该结点,!x代表不接入该结点),设它到边t的该侧端点的距离为d,则它要与该侧线段树上距离为d的结点u建立约束条件p[u][0]->x,p[u][1]->!x,并与另一侧线段树上距离范围在[L-(d+len(t)),R-(d+len(t))]内的结点u建立可能的四种约束条件{x->p[u][0],x->p[u][1],!x->p[u][0],!x->p[u][1]},然后跑2-SAT就行了。

    由于边分治最多往下递归$O(logn)$层,每层上的每个结点最多与线段树上$O(logn)$个结点连边,所以总复杂度为$O(nlog^2n)$

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int N=2e5+10,inf=0x3f3f3f3f;
      5 struct TWO_SAT {
      6     int n,hd[N*40],ne,mk[N*40],sta[N*40],tp;
      7     struct E {int v,nxt;} e[N*80];
      8     void link(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
      9     void link(int u,int v,int f,int g) {
     10         link(u<<1|f,v<<1|g);
     11         link(v<<1|(!g),u<<1|(!f));
     12     }
     13     void init(int _n) {
     14         n=_n,ne=tp=0;
     15         for(int i=0; i<=(n<<1|1); ++i)mk[i]=0,hd[i]=-1;
     16     }
     17     bool dfs(int u) {
     18         if(mk[u^1])return 0;
     19         if(mk[u])return 1;
     20         mk[u]=1,sta[tp++]=u;
     21         for(int i=hd[u]; ~i; i=e[i].nxt)if(!dfs(e[i].v))return 0;
     22         return 1;
     23     }
     24     bool check() {
     25         for(int i=1; i<=n; ++i)mk[i]=0;
     26         for(int i=1; i<=n; ++i)if(!mk[i<<1]&&!mk[i<<1|1]) {
     27                 tp=0;
     28                 if(!dfs(i<<1)) {
     29                     for(; tp; mk[sta[--tp]]=0);
     30                     if(!dfs(i<<1|1))return 0;
     31                 }
     32             }
     33         return 1;
     34     }
     35 } twosat;
     36 #define l(u) ch[u][0]
     37 #define r(u) ch[u][1]
     38 #define mid ((l+r)>>1)
     39 struct Segtree {
     40     int ch[N*40][2],RT[N],p[N*40][2],id[N],tot,tot2;
     41     int newnode() {int u=++tot; l(u)=r(u)=0; return u;}
     42     void init(int n) {
     43         tot=tot2=0;
     44         for(int i=1; i<=n; ++i)id[i]=++tot2;
     45     }
     46     void build(int& u,int l,int r) {
     47         u=newnode();
     48         p[u][0]=++tot2,p[u][1]=++tot2;
     49         if(l==r)return;
     50         build(l(u),l,mid),build(r(u),mid+1,r);
     51         twosat.link(p[u][0],p[l(u)][0],1,1),twosat.link(p[u][0],p[r(u)][0],1,1);
     52         twosat.link(p[u][1],p[l(u)][1],1,1),twosat.link(p[u][1],p[r(u)][1],1,1);
     53     }
     54     void upd1(int u,int v,int f,int g,int L,int R,int l,int r) {
     55         if(l>=L&&r<=R) {twosat.link(v,p[u][g],f,1); return;}
     56         if(l>R||r<L)return;
     57         upd1(l(u),v,f,g,L,R,l,mid),upd1(r(u),v,f,g,L,R,mid+1,r);
     58     }
     59     void upd2(int u,int v,int x,int l,int r) {
     60         if(l==r) {
     61             twosat.link(p[u][0],v,1,0);
     62             twosat.link(p[u][1],v,1,1);
     63             return;
     64         }
     65         x<=mid?upd2(l(u),v,x,l,mid):upd2(r(u),v,x,mid+1,r);
     66     }
     67 } tree;
     68 struct E {int v,c,nxt;} e[N];
     69 int a[N],hd[N],ne,n,m,siz[N],vis[N],tot,RT,mx,mxd,ds[N],Ll,Rr,rt[N],Mxd[N];
     70 void link(int u,int v,int c) {e[ne]= (E) {v,c,hd[u]},hd[u]=ne++;}
     71 vector<E> g[N];
     72 void rebuild(int u,int f) {
     73     int w=u;
     74     for(int i=hd[u]; ~i; i=e[i].nxt) {
     75         int v=e[i].v;
     76         if(v==f)continue;
     77         rebuild(v,u);
     78         g[w].push_back({v,1,0});
     79         if(~e[i].nxt&&~e[e[i].nxt].nxt)g[w].push_back({++tot,0,0}),w=tot;
     80     }
     81 }
     82 void rebuild() {
     83     tot=n,rebuild(1,0);
     84     memset(hd,-1,sizeof hd),ne=0;
     85     for(int i=1; i<=tot; ++i) {
     86         for(int j=0; j<g[i].size(); ++j)
     87             link(i,g[i][j].v,g[i][j].c),link(g[i][j].v,i,g[i][j].c);
     88         g[i].clear();
     89     }
     90 }
     91 void getrt(int u,int f,int sz) {
     92     siz[u]=1;
     93     for(int i=hd[u]; ~i; i=e[i].nxt) {
     94         int v=e[i].v;
     95         if(vis[i]||v==f)continue;
     96         getrt(v,u,sz),siz[u]+=siz[v];
     97         int t=max(siz[v],sz-siz[v]);
     98         if(t<mx)mx=t,RT=i;
     99     }
    100 }
    101 void getdis(int u,int f,int d) {
    102     ds[u]=d,mxd=max(mxd,d);
    103     for(int i=hd[u]; ~i; i=e[i].nxt) {
    104         int v=e[i].v,c=e[i].c;
    105         if(vis[i]||v==f)continue;
    106         getdis(v,u,d+c);
    107     }
    108 }
    109 void buildedge(int u,int f,int t) {
    110     tree.upd2(rt[t],tree.id[u],ds[u],0,Mxd[t]);
    111     for(int i=0; i<=3; ++i)if(a[u]>>i&1)
    112             tree.upd1(rt[t^1],tree.id[u],i>>1&1,i&1,Ll-(ds[u]+e[t^1].c),Rr-(ds[u]+e[t^1].c),0,Mxd[t^1]);
    113     for(int i=hd[u]; ~i; i=e[i].nxt) {
    114         int v=e[i].v;
    115         if(vis[i]||v==f)continue;
    116         buildedge(v,u,t);
    117     }
    118 }
    119 void cal(int t) {tree.build(rt[t],0,Mxd[t]=mxd);}
    120 void solve(int u,int f,int sz) {
    121     if(sz==1)return;
    122     mx=inf,getrt(u,0,sz);
    123     int t=RT;
    124     vis[t]=vis[t^1]=1;
    125     mxd=0,getdis(e[t].v,0,0),cal(t);
    126     mxd=0,getdis(e[t^1].v,0,0),cal(t^1);
    127     buildedge(e[t].v,0,t),buildedge(e[t^1].v,0,t^1);
    128     int a=siz[e[t].v],b=sz-siz[e[t].v];
    129     solve(e[t].v,RT,a),solve(e[t^1].v,t^1,b);
    130 }
    131 int main() {
    132     memset(hd,-1,sizeof hd),ne=0;
    133     scanf("%d%d%d%d",&n,&m,&Ll,&Rr);
    134     for(int i=1; i<n; ++i) {
    135         int u,v;
    136         scanf("%d%d",&u,&v);
    137         link(u,v,0);
    138         link(v,u,0);
    139     }
    140     while(m--) {
    141         int u,f;
    142         scanf("%d%d",&u,&f);
    143         a[u]|=1<<f;
    144     }
    145     rebuild();
    146     twosat.init(tot*30);
    147     tree.init(tot);
    148     solve(1,0,tot);
    149     puts(twosat.check()?"YES":"NO");
    150     return 0;
    151 }
  • 相关阅读:
    C实现类封装、继承、多态
    运算符重载详解
    类定义 对象数组
    Install KVM Hypervisor on arrch64 Linux Server
    Failed to load package MonoAndroidDesignerPackage
    C# is和as操作符
    C#中out和ref之间的区别
    C#中 const 和 readonly 的区别
    C#版本和.NET版本以及VS版本的对应关系
    各类纤程/协程使用比较
  • 原文地址:https://www.cnblogs.com/asdfsag/p/12684323.html
Copyright © 2011-2022 走看看