标签: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