题解--布尔
简要题意:问区间能最少划分成段,每一段 2-SAT 判断为
10~40pts
很明显需要维护一个
求的方法是用 2-SAT,每次
当然由于连的是双向边可以把 tarjan 换成并查集。
100pts
进行分析,发现
定义
求
非法的判定可以用加边后
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+5,maxm=1e5+5;
char __buf[1<<21],*__p1,*__p2;
#define getchar() (__p1==__p2?(__p2=__buf+fread(__p1=__buf,1,1<<21,stdin),__p1==__p2?EOF:*__p1++):*__p1++)
inline int read() {
int __x=0;
char __c=getchar();
while(__c<'0'||__c>'9') __c=getchar();
while(__c>='0'&&__c<='9') {
__x=__x*10+__c-'0';
__c=getchar();
}
return __x;
}
inline char pc(char ch,bool bj) {
static char buf[1<<18],*p1=buf,*p2=buf+(1<<18);
return ((bj)||(*p1++=ch)&&p1==p2)&&fwrite(p1=buf,1,p1-buf,stdout),0;
}
void print(int x) {
if(x<0)x=-x,pc('-',0);
if(x>9)print(x/10);
pc(x%10^48,false);
}
inline void printnum(int x,int ch) {
print(x),pc(ch,false);
}
struct oper {
int op,x,y;
oper() {}
oper(int Op,int X,int Y) {
op=Op,x=X,y=Y;
}
} o[maxn*4];
int u[maxn],v[maxn],oc,n,m,ans[maxn],f[maxm*2],siz[maxm*2],q,g[maxn][20],zm[maxn];
int getf(int x) {
return f[x]==x?x:getf(f[x]);
}
int opp(int x) {
return x&1?x+1:x-1;
}
void merge(int x,int y) {
x=getf(x),y=getf(y);
if(x==y)return;
if(siz[x]<siz[y])swap(x,y);
o[++oc]=oper(0,y,0),f[y]=x;
o[++oc]=oper(1,x,siz[y]),siz[x]+=siz[y];
}
void replace(int cas) {
while(oc>cas) {
int op=o[oc].op,x=o[oc].x,y=o[oc].y;
if(!op)f[x]=x;
if(op==1)siz[x]-=y;
oc--;
}
}
bool check(int x) {
return getf(x)==getf(opp(x));
}
void solve(int l,int r,int L,int R,bool lst) {
if(L==R) {
for(register int i=l; i<=r; i++)ans[i]=L;
return;
}
if(l>r)return;
int mid=(l+r)/2,cas=oc;
bool now=lst;
for(register int i=mid; i<=r&&i<L; i++) {
merge(u[i],v[i]),merge(opp(u[i]),opp(v[i]));
now|=check(u[i]);
if(now)break;
}//mid~min(r,L-1) 的边是一定要用的,先加上
int tmp=oc,sum=now;
for(register int i=max(L,mid); i<=R; i++) {
merge(u[i],v[i]),merge(opp(u[i]),opp(v[i]));
now|=check(u[i]);
if(now) {
ans[mid]=i;
break;
}
}//从 max(L,mid) 一直加到 R 来寻找 mid 处答案
bool pd=0;
if(!ans[mid]) {
ans[mid]=m+1;
for(register int i=mid+1; i<=r; i++)ans[i]=m+1;
pd=1;
}//如果到最右边仍然合法,那么它的右区间也合法
replace(tmp);
solve(l,mid-1,L,ans[mid],sum);//l~mid-1 需要 mid~min(r,L-1) 的边
replace(cas);
if(pd)return;
now=lst;
for(register int i=max(r+1,L); i<ans[mid]; i++) {
merge(u[i],v[i]),merge(opp(u[i]),opp(v[i]));
now|=check(u[i]);
if(now)break;
}
solve(mid+1,r,ans[mid],R,now);//mid+1,~r 需要 max(r+1,L)~ans[mid]-1 的边
replace(cas);
}
int main() {
int U,x,V,y;
bool p=0;
n=read(),m=read(),q=read();
for(register int i=1; i<=2*n; i++)f[i]=i,siz[i]=1;
for(register int i=1; i<=m; i++) {
U=read(),x=read(),V=read(),y=read();
zm[i]=zm[i-1]+(U==V&&x!=y);
u[i]=U*2-1+x,v[i]=V*2-1+y;
merge(u[i],v[i]),merge(opp(u[i]),opp(v[i]));
p|=check(u[i]);
}
if(!p) {
while(q--)printnum(1,'\n');
return pc(0,1),0;
}
replace(0);
u[m+1]=1,v[m+1]=2;
solve(1,m,1,m+1,0);
for(register int i=0; i<20; i++)g[m+1][i]=m+1;
for(register int i=m; i; i--) {
g[i][0]=ans[i];
for(register int j=1; j<20; j++)g[i][j]=g[g[i][j-1]][j-1];
}
while(q--) {
x=read(),y=read();
if(zm[y]-zm[x-1]>0) {
printnum(-1,'\n');
continue;
}
int w=1;
for(register int i=19; i>=0; i--)
if(g[x][i]<=y)x=g[x][i],w+=(1<<i);
printnum(w,'\n');
}
pc(0,1);
return 0;
}