专栏文章
ARC190E
AT_arc190_e题解参与者 2已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @miqikjoq
- 此快照首次捕获于
- 2025/12/04 05:23 3 个月前
- 此快照最后确认于
- 2025/12/04 05:23 3 个月前
一个全新的领域!
众所周知,二分图最大匹配为:,霍尔定理推论。
霍尔定理相关题目已经出了很多很多,诞生了许多好题。
聪明的出题人一定不会满足于此,走向全新的领域:一般图!
一般图最大匹配为:,其中 表示把图扣去集合 中的点之后大小为奇数的连通块个数,在学术上被称作:Tutte-Berge Formula。证明部分略去,有兴趣自行了解(我还不太会,待学习)
言归正传,那么本题先可以简单得建立出一般图最大匹配模型:两个距离小于等于 的点之间连一条边,保留区间中的所有点,跑最大匹配。
那么我们现在只用考虑求 。
注意到这里是带权的最大匹配(每个点包含了 个点),可以发现一个点要么全部选入 ,要么全没有选入 ,具体而言,假设最终 中选了 个点,那么调整成选 个点一定不劣。
不妨设 表示下标 的所有点选/没选入 ,考虑设计 转移。
不妨设区间长度为 ,以及 ,方便处理边界。
首先答案为奇 连通块个数减去所有 的带权和,当然会有细节需要你考虑。
当一个 形成一个独立连通块时,贡献为 并非 (每个点都是孤立的)
出现时即中间只有一个 间断两边的 其实是一个连通块,这种情况是烦人的,但是你直接钦定全局不能出现这种情况即可(有支配性:不如把 改为 ,可调整证明)
的时候是不能选 的,但是 不劣于 的,所以不需要特殊处理。
然后就可以 转移了,设 表示当前考虑了 , 号点当前状态为:单独的一个 ,在多个 的连通块内,单独的一个 ,在多个 的联通块内且当前连通块大小为偶数/奇数。
列出矩阵 (max+)做转移即可,细节看代码。
复杂度 , 为矩阵大小,本题还能支持单点修改。
一道很牛牛的题,感觉这个结论扩展性极强,期待下一次遇见。
CPP#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+3,K=5,INF=1e18;
ll n,m,a[N],sa[N];
void Max(ll &x,ll y){if(x<y)x=y;}
struct Mat
{
array<ll,K>f[K];
auto& operator[](int x){return f[x];}
void Clear(){memset(f,0xcf,sizeof(f));}
friend Mat operator *(Mat A,Mat B)
{
Mat C;C.Clear();
for(int i=0;i<K;i++)for(int k=0;k<K;k++)for(int j=0;j<K;j++)
Max(C[i][j],A[i][k]+B[k][j]);
return C;
}
}I;
void Init(){for(int i=0;i<K;i++)for(int j=0;j<K;j++)I[i][j]=i==j?0:-INF;}
Mat Get(ll v)
{
Mat A;
if(v%2==0)
{
A[0]={-INF,-v,-INF,-INF,-INF};
A[1]={-INF,-v,v,0,-INF};
A[2]={-v,-INF,-INF,-INF,-INF};
A[3]={-v,-INF,-INF,0,-INF};
A[4]={-v,-INF,-INF,-INF,0};
}
else
{
A[0]={-INF,-v,-INF,-INF,-INF};
A[1]={-INF,-v,v,-INF,1};
A[2]={-v,-INF,-INF,-INF,-INF};
A[3]={-v,-INF,-INF,-INF,1};
A[4]={-v,-INF,-INF,-1,-INF};
}
return A;
}
struct SGT
{
int DT;Mat tr[1<<19|3];
void Up(int p){tr[p]=tr[p<<1]*tr[p<<1|1];}
void Build()
{
DT=1<<(__lg(n)+1);
for(int i=1;i<=n;i++)tr[i+DT]=Get(a[i]);
for(int i=DT-1;i;i--)Up(i);
}
Mat Ask(int l,int r)
{
Mat sl=I,sr=I;
for(l+=DT-1,r+=DT+1;l+1!=r;l>>=1,r>>=1)
{
if(~l&1)sl=sl*tr[l+1];
if(r&1)sr=tr[r-1]*sr;
}
return sl*sr;
}
}T;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;Init();
for(int i=1;i<=n;i++)cin>>a[i],sa[i]=sa[i-1]+a[i];
T.Build();
for(int i=1,l,r;i<=m;i++)
{
cin>>l>>r;Mat t=T.Ask(l,r);
ll ans=*max_element(t[1].begin(),t[1].end());
cout<<(sa[r]-sa[l-1]-ans)/2<<"\n";
}
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...