专栏文章
题解:P14532 [RMI 2018] 颜色 / Colors
P14532题解参与者 2已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @min5vwhx
- 此快照首次捕获于
- 2025/12/01 21:05 3 个月前
- 此快照最后确认于
- 2025/12/01 21:05 3 个月前
先考虑一个正确的操作方式,由于点权是不能变大的,所以把目标点权最大的挑出来,设为 ,点权比 大的点都是无意义的,需要找一个小于等于 的最大点权进行覆盖,且只能操作这些点,然后把目标点权为 的点删掉,直到全部点都删光为止。发现这样会进行很多无意义赋值,考虑直接跳到 等于这个点目标点权的时刻,发现此时 的点已经被删光了, 的点不能操作,所以能操作的点必须满足 ,能操作的边必须两个端点都满足这个限制,只要在当前点的连通块内有一个点满足 即合法,充要性是显然的。
因此考虑线段树分治,按秩合并并查集,启发式合并 unordered_multiset,注意 erase 函数会将整个 multiset 中所有值为 的元素全部删掉,所以要使用 find 找出一个后再 erase。时间复杂度应该是 的。
CPP#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5,M=4e5+5;
int flag,a[N],b[N],f[N],h[N],tp=0;
struct node2{int x,y,z;}st[M];
struct node{int x,y;}s[M];
vector<int> e[N<<2],pt[N];
unordered_multiset<int> ex[N];
void add(int u,int l,int r,int x,int y,int z){
if(x<=l && r<=y){
e[u].emplace_back(z);
return;
}
int mid=l+r>>1;
if(x<=mid) add(u<<1,l,mid,x,y,z);
if(mid<y) add(u<<1|1,mid+1,r,x,y,z);
return;
}
int find(int x){
if(x==f[x]) return x;
return find(f[x]);
}
void merge(int x,int y,int u){
int fx=find(x),fy=find(y);
if(fx==fy) return;
tp++;
st[tp].x=u;
if(h[fx]>h[fy]){
f[fy]=fx;
st[tp].y=fy;
if(ex[fx].size()<ex[fy].size()){
swap(ex[fx],ex[fy]);
st[tp].z=1;
}
else st[tp].z=0;
for(auto it:ex[fy]) ex[fx].insert(it);
}
else if(h[fx]<h[fy]){
f[fx]=fy;
st[tp].y=fx;
if(ex[fy].size()<ex[fx].size()){
swap(ex[fx],ex[fy]);
st[tp].z=1;
}
else st[tp].z=0;
for(auto it:ex[fx]) ex[fy].insert(it);
}
else {
f[fy]=fx;h[fx]++;h[fy]++;
st[tp].y=fy;
if(ex[fx].size()<ex[fy].size()){
swap(ex[fx],ex[fy]);
st[tp].z=1;
}
else st[tp].z=0;
for(auto it:ex[fy]) ex[fx].insert(it);
}
return;
}
void dg(int u,int l,int r){
for(auto it:e[u]) merge(s[it].x,s[it].y,u);
if(l==r){
for(auto it:pt[l]){
int x=find(it);
if(ex[x].find(l)==ex[x].end()){
flag=1;
break;
}
}
}
else {
int mid=l+r>>1;
dg(u<<1,l,mid);
dg(u<<1|1,mid+1,r);
}
while(tp>0 && st[tp].x==u){
int x=st[tp].y,z=st[tp].z;
if(h[x]==h[f[x]]) h[x]--,h[f[x]]--;
for(auto it:ex[x]) ex[f[x]].erase(ex[f[x]].find(it));
if(z) swap(ex[x],ex[f[x]]);
f[x]=x;tp--;
}
e[u].clear();
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
while(T--){
int n,m;flag=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
cin>>b[i];
if(a[i]<b[i]) flag=1;
pt[b[i]].emplace_back(i);
f[i]=i,h[i]=1;
ex[i].insert(a[i]);
}
for(int i=1,x,y,l,r;i<=m;i++){
cin>>x>>y;
s[i].x=x,s[i].y=y;
l=max(b[x],b[y]);
r=min(a[x],a[y]);
if(l<=r) add(1,1,n,l,r,i);
}
dg(1,1,n);
if(flag==1) cout<<"0\n";
else cout<<"1\n";
for(int i=1;i<=n;i++){
ex[i].clear();
pt[i].clear();
}
}
return 0;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...