- 線段樹最佳化建圖
- 一般用動態開點線段樹實現
- 建立對稱的入樹和出樹
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
vector<int>a[600005];
int c[100005],cnt,tot,sum,id[600005],dfn[600005],low[600005],val[100005],n,m;
stack<int>s;
bool v[600005],h[600005];
int root1,root2;
int read1()
{
char cc=getchar();
while(!(cc>=48&&cc<=57))
{
if(cc=='-')
{
break;
}
cc=getchar();
}
bool f=false;
int s=0;
if(cc=='-')
{
f=true;
}
else
{
s=cc-48;
}
while(1)
{
cc=getchar();
if(cc>=48&&cc<=57)
{
s=s*10+cc-48;
}
else
{
break;
}
}
if(f==true)
{
s=-s;
}
return s;
}
struct t1
{
int l,r;
}t[600005];
struct w1
{
int va,id;
}w[100005];
int tmp[100005];
bool cmp(w1 a,w1 b)
{
return a.va<b.va;
}
int build1(int l,int r)
{
int p;
if(l==r)
{
p=l;
return p;
}
else
{
p=++tot;
a[p].clear();
}
int mid=(l+r)>>1;
t[p].l=build1(l,mid);
t[p].r=build1(mid+1,r);
a[p].push_back(t[p].l);
a[p].push_back(t[p].r);
return p;
}
int build2(int l,int r)
{
int p;
if(l==r)
{
p=l;
return p;
}
else
{
p=++tot;
a[p].clear();
}
int mid=(l+r)>>1;
t[p].l=build2(l,mid);
t[p].r=build2(mid+1,r);
a[t[p].l].push_back(p);
a[t[p].r].push_back(p);
return p;
}
void change1(int p,int pl,int pr,int l,int r,int c,int opt)
{
if(l<=pl&&r>=pr)
{
if(opt==1)
{
a[c].push_back(p);
}
else
{
a[c].pop_back();
}
}
else
{
int mid=(pl+pr)>>1;
if(l<=mid)
{
change1(t[p].l,pl,mid,l,r,c,opt);
}
if(r>mid)
{
change1(t[p].r,mid+1,pr,l,r,c,opt);
}
}
}
void change2(int p,int pl,int pr,int l,int r,int c,int opt)
{
if(l<=pl&&r>=pr)
{
if(opt==1)
{
a[p].push_back(c);
}
else
{
a[p].pop_back();
}
}
else
{
int mid=(pl+pr)>>1;
if(l<=mid)
{
change2(t[p].l,pl,mid,l,r,c,opt);
}
if(r>mid)
{
change2(t[p].r,mid+1,pr,l,r,c,opt);
}
}
}
void tarjan(int n1)
{
v[n1]=true;
s.push(n1);
h[n1]=true;
dfn[n1]=++tot;
low[n1]=dfn[n1];
for(int i=0;i<a[n1].size();i++)
{
if(v[a[n1][i]]==false)
{
tarjan(a[n1][i]);
low[n1]=min(low[n1],low[a[n1][i]]);
}
else if(h[a[n1][i]]==true)
{
low[n1]=min(low[n1],dfn[a[n1][i]]);
}
}
if(dfn[n1]==low[n1])
{
cnt++;
while(!s.empty())
{
if(s.top()==n1)
{
break;
}
h[s.top()]=false;
id[s.top()]=cnt;
s.pop();
}
h[n1]=false;
id[n1]=cnt;
s.pop();
}
}
bool solve()
{
for(int i=1;i<=6*n;i++)
{
dfn[i]=0;
v[i]=false;
}
tot=cnt=0;
for(int i=1;i<=6*n;i++)
{
if(dfn[i]==0)
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
if(id[val[i]]==id[val[i]+n])
{
return false;
}
c[i]=id[val[i]]>id[val[i]+n];
}
return true;
}
void change(int maxn,int opt)
{
for(int i=1;i<=n;i++)
{
int j=upper_bound(tmp+i+1,tmp+n+1,tmp[i]+maxn)-tmp;
if(j!=n+1)
{
change1(root1,1,2*n,j,n,i+n,opt);
change2(root2,1,2*n,j+n,n+n,i,opt);
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
n=read1();
m=read1();
for(int i=1;i<=n;i++)
{
w[i].va=read1();
w[i].id=i;
}
sort(w+1,w+n+1,cmp);
for(int i=1;i<=n;i++)
{
val[w[i].id]=i;
tmp[i]=w[i].va;
}
for(int i=1;i<=2*n;i++)
{
a[i].clear();
}
tot=2*n;
root1=build1(1,2*n);
root2=build2(1,2*n);
for(int i=1;i<=m;i++)
{
int x,y,l,r;
x=read1();
y=read1();
l=read1();
r=read1();
if(l==0&&r==2)
{
}
else if(l==r)
{
if(l==0)
{
a[val[x]+n].push_back(val[x]);
a[val[y]+n].push_back(val[y]);
}
else if(l==2)
{
a[val[x]].push_back(val[x]+n);
a[val[y]].push_back(val[y]+n);
}
else
{
a[val[x]].push_back(val[y]+n);
a[val[y]+n].push_back(val[x]);
a[val[y]].push_back(val[x]+n);
a[val[x]+n].push_back(val[y]);
}
}
else
{
if(l==0)
{
a[val[x]+n].push_back(val[y]);
a[val[y]+n].push_back(val[x]);
}
else
{
a[val[x]].push_back(val[y]+n);
a[val[y]].push_back(val[x]+n);
}
}
}
int l=0,r=2e8;
while(l<r)
{
int mid=(l+r)>>1;
change(mid,1);
bool tmp=solve();
if(tmp==true)
{
r=mid;
}
else
{
l=mid+1;
}
change(mid,-1);
}
change(l,1);
bool tmp=solve();
if(tmp==false)
{
puts("-1");
continue;
}
printf("%d\n",l);
for(int i=1;i<=n;i++)
{
if(c[i]==1)
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
}
return 0;
}