loj#2740. 「JOISC 2016 Day 4」最差记者 2

为啥网上这题很少有题解啊。

首先,改 A 和改 C 是一样的,我们考虑只改 C。让 D 去匹配 B。

有一个比较好想的做法,先考虑能够同国匹配的就先匹配掉(这个可以用 multiset),剩余的,考虑按值域来(实际上离散化后就是跟按序列一样),对于 Di,那么所对应 Bj 的值域在 [Di,max]

那么,分成 2 个部分,将 D 部的 i 连向 B 部的 [Di,max] 这些点。那么,我们只需要看看有没有完美匹配即可。

假如同国匹配的全都匹配掉之后再去看看有没有完美匹配,则可能不行。

我们要让最后一定有完美匹配,所以对于同国能匹配的,还要判断删去 D 部这个点,还能不能形成完美匹配。

但这样复杂度是 O(n2n) 级别的。

考虑只需要判断有没有,想到 hall 定理。

|could(S)||S|0

按照套路维护前缀 |could(S)|,|S|。对于 Di,那么会对 |S| 有贡献(我们是让 D 部匹配 B 部嘛)贡献范围是 [Di,max] (前缀集合大小贡献),对于 Bi,对 |could(S)| 有贡献,贡献范围是 [Bi,max],即对于 Dj[Bi,max],才可能匹配它。

这个样子相当于 +1,用线段树维护前缀最小值即可。(注意是前缀,因为要表示子集!!!为什么可以看另一道相似的题目的题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<code-pre class="code-pre" id="pre-NkiaBi"><code-line class="line-numbers-rows"></code-line>#include <cstdio>
<code-line class="line-numbers-rows"></code-line>#include <algorithm>
<code-line class="line-numbers-rows"></code-line>#include <iostream>
<code-line class="line-numbers-rows"></code-line>#include <cstring>
<code-line class="line-numbers-rows"></code-line>#include <vector>
<code-line class="line-numbers-rows"></code-line>#include <cmath>
<code-line class="line-numbers-rows"></code-line>#include <queue>
<code-line class="line-numbers-rows"></code-line>#include <map>
<code-line class="line-numbers-rows"></code-line>#include <set>
<code-line class="line-numbers-rows"></code-line>#define ll long long
<code-line class="line-numbers-rows"></code-line>
<code-line class="line-numbers-rows"></code-line>using namespace std;
<code-line class="line-numbers-rows"></code-line>int rd() {
<code-line class="line-numbers-rows"></code-line>   int f=1,sum=0; char ch=getchar();
<code-line class="line-numbers-rows"></code-line>   while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
<code-line class="line-numbers-rows"></code-line>   while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
<code-line class="line-numbers-rows"></code-line>   return sum*f;
<code-line class="line-numbers-rows"></code-line>}
<code-line class="line-numbers-rows"></code-line>ll lrd() {
<code-line class="line-numbers-rows"></code-line>   ll f=1,sum=0; char ch=getchar();
<code-line class="line-numbers-rows"></code-line>   while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
<code-line class="line-numbers-rows"></code-line>   while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
<code-line class="line-numbers-rows"></code-line>   return sum*f;
<code-line class="line-numbers-rows"></code-line>}
<code-line class="line-numbers-rows"></code-line>/*
<code-line class="line-numbers-rows"></code-line>考虑改A和改C没区别
<code-line class="line-numbers-rows"></code-line>让结束的这一部去匹配之前的那一部
<code-line class="line-numbers-rows"></code-line>且维护线段树前缀和,这时对于点数就不一定是 l 了
<code-line class="line-numbers-rows"></code-line>可以考虑动态加
<code-line class="line-numbers-rows"></code-line>*/
<code-line class="line-numbers-rows"></code-line>#define ls (cur<<1)
<code-line class="line-numbers-rows"></code-line>#define rs (ls|1)
<code-line class="line-numbers-rows"></code-line>#define int ll
<code-line class="line-numbers-rows"></code-line>const int N=(int)(5e5+5);
<code-line class="line-numbers-rows"></code-line>multiset<int>s[N];
<code-line class="line-numbers-rows"></code-line>multiset<int>::iterator it;
<code-line class="line-numbers-rows"></code-line>int mi[N<<2],tag[N<<2],A[N],B[N],C[N],D[N],lsh[N<<1],tot,n;
<code-line class="line-numbers-rows"></code-line>
<code-line class="line-numbers-rows"></code-line>void push_up(int cur) {
<code-line class="line-numbers-rows"></code-line>   mi[cur]=min(mi[ls],mi[rs]);
<code-line class="line-numbers-rows"></code-line>}
<code-line class="line-numbers-rows"></code-line>
<code-line class="line-numbers-rows"></code-line>void push_down(int cur) {
<code-line class="line-numbers-rows"></code-line>   if(!tag[cur]) return ;
<code-line class="line-numbers-rows"></code-line>   tag[ls]+=tag[cur]; tag[rs]+=tag[cur];
<code-line class="line-numbers-rows"></code-line>   mi[ls]+=tag[cur]; mi[rs]+=tag[cur];
<code-line class="line-numbers-rows"></code-line>   tag[cur]=0;
<code-line class="line-numbers-rows"></code-line>}
<code-line class="line-numbers-rows"></code-line>
<code-line class="line-numbers-rows"></code-line>void update(int cur,int l,int r,int cl,int cr,int v) {
<code-line class="line-numbers-rows"></code-line>   if(cl<=l&&r<=cr) return mi[cur]+=v,tag[cur]+=v,void();
<code-line class="line-numbers-rows"></code-line>   push_down(cur);
<code-line class="line-numbers-rows"></code-line>   int mid=(l+r)>>1;
<code-line class="line-numbers-rows"></code-line>   if(cl<=mid) update(ls,l,mid,cl,cr,v);
<code-line class="line-numbers-rows"></code-line>   if(cr>mid) update(rs,mid+1,r,cl,cr,v);
<code-line class="line-numbers-rows"></code-line>   push_up(cur);
<code-line class="line-numbers-rows"></code-line>}
<code-line class="line-numbers-rows"></code-line>
<code-line class="line-numbers-rows"></code-line>signed main() {
<code-line class="line-numbers-rows"></code-line>   n=rd();
<code-line class="line-numbers-rows"></code-line>   for(int i=1;i<=n;i++) A[i]=rd(),B[i]=rd(),lsh[++tot]=B[i];
<code-line class="line-numbers-rows"></code-line>   for(int i=1;i<=n;i++) C[i]=rd(),D[i]=rd(),lsh[++tot]=D[i];
<code-line class="line-numbers-rows"></code-line>   sort(lsh+1,lsh+1+tot); tot=unique(lsh+1,lsh+1+tot)-lsh-1;
<code-line class="line-numbers-rows"></code-line>   for(int i=1;i<=n;i++) {
<code-line class="line-numbers-rows"></code-line>       B[i]=lower_bound(lsh+1,lsh+1+tot,B[i])-lsh; D[i]=lower_bound(lsh+1,lsh+1+tot,D[i])-lsh;
<code-line class="line-numbers-rows"></code-line>       s[A[i]].insert(B[i]);
<code-line class="line-numbers-rows"></code-line>       update(1,1,tot,B[i],tot,1); //匹配的点数,只能是之后的
<code-line class="line-numbers-rows"></code-line>       update(1,1,tot,D[i],tot,-1); //前缀的集合+1
<code-line class="line-numbers-rows"></code-line>   }
<code-line class="line-numbers-rows"></code-line>   int ans=0;
<code-line class="line-numbers-rows"></code-line>   for(int i=n;i>=1;i--) {
<code-line class="line-numbers-rows"></code-line>       it=s[C[i]].upper_bound(D[i]);
<code-line class="line-numbers-rows"></code-line>       if(it==s[C[i]].begin()) ++ans;
<code-line class="line-numbers-rows"></code-line>       else {
<code-line class="line-numbers-rows"></code-line>           --it; int qwq=*it;
<code-line class="line-numbers-rows"></code-line>           s[C[i]].erase(it);
<code-line class="line-numbers-rows"></code-line>           update(1,1,tot,qwq,tot,-1); update(1,1,tot,D[i],tot,1);
<code-line class="line-numbers-rows"></code-line>           if(mi[1]<0) { //剩下的没有完美匹配
<code-line class="line-numbers-rows"></code-line>               s[C[i]].insert(qwq); ++ans;
<code-line class="line-numbers-rows"></code-line>               update(1,1,tot,qwq,tot,1); update(1,1,tot,D[i],tot,-1);
<code-line class="line-numbers-rows"></code-line>           }
<code-line class="line-numbers-rows"></code-line>       }
<code-line class="line-numbers-rows"></code-line>   }
<code-line class="line-numbers-rows"></code-line>   printf("%lld",ans); return 0;
<code-line class="line-numbers-rows"></code-line>}
</code-pre>

  


__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/15211229.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(243)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示