码迷,mamicode.com
首页 > Web开发 > 详细

LibreOJ - 571 Misaka Network 与 Accelerator (边分治+线段树+2-SAT)

时间:2020-04-12 12:38:10      阅读:108      评论:0      收藏:0      [点我收藏+]

标签:inf   mis   点距   ||   线段树   network   nbsp   build   put   

题目链接

很明显的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(log^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 }

 

LibreOJ - 571 Misaka Network 与 Accelerator (边分治+线段树+2-SAT)

标签:inf   mis   点距   ||   线段树   network   nbsp   build   put   

原文地址:https://www.cnblogs.com/asdfsag/p/12684323.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!