题意:

有 n 群怨灵排成一排,燐每秒钟会选择一段区间,消灭至多 k 只怨灵。

如果怨灵数量不足 k,则会消灭尽量多的怨灵。

燐作为一只有特点的猫,它选择的区间是不会相互包含的。它想要知道它每秒最多能消灭多少怨灵。

要求:在之前每次都消灭尽量多的怨灵的情况下,求第 i 秒最多能消灭的怨灵的数量。

首先,这题可以用网络流做部分分。

考虑如何判断是否可行:

有一种显然的二分图匹配:把每个询问放在X部,怨灵放在Y部。

然后,把询问,怨灵分别拆点,进行区间连边,做匹配,如果有完美匹配,则可行。

但是,如果直接而匹配,会超时。我们考虑使用Hall定理进行判断。

Hall定理,就是说,在X部上取任意子集,与其相连的Y部结点都不小于集合大小。

如果我们要取子集,会变得更慢。

首先,把区间排序。

通过分析,我们知道:只要判断连续区间即可。

在X不连续时:

1、X部中一个点拆出来的点选子集,不如都选,因为都选不会使Y部大小增加。、

2、类似的,若X部中选的点在Y部中连续,那么X一定要连续,因为中间增加不会使Y部大小增加(区间是不会相互包含的)。

3、若X部中选的点在Y部中不连续,那可以拆成多个,拆的前后是等价的。

所以,我们只要快速判断连续区间就行。

记怨灵数量的前缀和为 sum[i],区间消灭的怨灵数量的前缀和为 sumval[i],区间左右端点为 l[i],r[i]。

那么我们要求对于任意 \(1\leq L\leq R\leq m\),满足:

\(sumval[R]-sumval[L-1]\leq sum[r[R]]-sum[l[L]-1]\)

即\(sumval[R]-sum[r[R]]\leq sumval[L-1]-sum[l[L]-1]\)。

由于sum不变,只有sumval会边,所以当区间 i 被加入时:

若L-1>=i,R>=i,那么大小关系不变。

若L-1<i,R<i,那么大小关系不变。

只有对L-1<i,R>=i,即L<=i,R>=i 的情况产生影响。

所以区间 i 被加入时设结果为val[i],那么对于任意 \(1\leq L\leq i\leq R\leq m\),要求 val[i]满足:

\(sumval[R]+val[i]-sum[r[R]]\leq sumval[L-1]-sum[l[L]-1]\)

即\(val[i]\leq sumval[L-1]-sum[l[L]-1]]-(sumval[R]-sum[r[R]])\)。

那么,找到最小的 \(sumval[L-1]-sum[l[L]-1]\),最大的 \(sumval[R]-sum[r[R]]\),相减就是 val[i]的值。(当然,如果 k 小于这个值的话,val[i]就是 k)

使用线段树,支持区间加,区间最值,即可实现上述操作。

时间复杂度:\(O(mlog_2 m)\)。

感觉这个思路非常巧妙。

代码:

#include <stdio.h>
#include <stdlib.h>
#define inf 2000000000
int sz[100010],px[100010],wz[100010];
int xl[100010],xr[100010],xk[100010];
int cmp(const void*a,const void*b)
{
return xl[*(int*)a]-xl[*(int*)b];
}
int z1[400010],z2[400010],su[100010];
int l1[400010],l2[400010];
void pushup(int i)
{
z1[i]=z1[(i<<1)|1];
z2[i]=z2[(i<<1)|1];
if(z1[i<<1]<z1[i])
z1[i]=z1[i<<1];
if(z2[i<<1]>z2[i])
z2[i]=z2[i<<1];
}
void pushdown(int i)
{
l1[i<<1]+=l1[i];
l1[(i<<1)|1]+=l1[i];
z1[i<<1]+=l1[i];
z1[(i<<1)|1]+=l1[i];
l1[i]=0;
l2[i<<1]+=l2[i];
l2[(i<<1)|1]+=l2[i];
z2[i<<1]+=l2[i];
z2[(i<<1)|1]+=l2[i];
l2[i]=0;
}
void jianshu(int i,int l,int r)
{
if(l+1==r)
{
z1[i]=-su[xl[px[l]]-1];
z2[i]=-su[xr[px[l]]];
return;
}
int m=(l+r)>>1;
jianshu(i<<1,l,m);
jianshu((i<<1)|1,m,r);
pushup(i);
}
void xiugai1(int i,int l,int r,int L,int R,int x)
{
if(R<=l||r<=L)
return;
if(L<=l&&r<=R)
{
z1[i]+=x;
l1[i]+=x;
return;
}
int m=(l+r)>>1;
pushdown(i);
xiugai1(i<<1,l,m,L,R,x);
xiugai1((i<<1)|1,m,r,L,R,x);
pushup(i);
}
void xiugai2(int i,int l,int r,int L,int R,int x)
{
if(R<=l||r<=L)
return;
if(L<=l&&r<=R)
{
z2[i]+=x;
l2[i]+=x;
return;
}
int m=(l+r)>>1;
pushdown(i);
xiugai2(i<<1,l,m,L,R,x);
xiugai2((i<<1)|1,m,r,L,R,x);
pushup(i);
}
void xiugai(int n,int j,int x)
{
xiugai1(1,1,n+1,j+1,n+1,x);
xiugai2(1,1,n+1,j,n+1,x);
}
int getz1(int i,int l,int r,int L,int R)
{
if(R<=l||r<=L)
return inf;
if(L<=l&&r<=R)
return z1[i];
int m=(l+r)>>1;
pushdown(i);
int rt1=getz1(i<<1,l,m,L,R),rt2=getz1((i<<1)|1,m,r,L,R);
if(rt1<rt2)return rt1;
else return rt2;
}
int getz2(int i,int l,int r,int L,int R)
{
if(R<=l||r<=L)
return -inf;
if(L<=l&&r<=R)
return z2[i];
int m=(l+r)>>1;
pushdown(i);
int rt1=getz2(i<<1,l,m,L,R),rt2=getz2((i<<1)|1,m,r,L,R);
if(rt1>rt2)return rt1;
else return rt2;
}
int getans(int n,int x)
{
int x1=getz1(1,1,n+1,1,x+1);
int x2=getz2(1,1,n+1,x,n+1);
return x1-x2;
}
int main()
{
freopen("rin.in","r",stdin);
freopen("rin.out","w",stdout);
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&sz[i]);
su[i]=su[i-1]+sz[i];
}
scanf("%d",&m);
if(m==0)return 0;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&xl[i],&xr[i],&xk[i]);
for(int i=1;i<=m;i++)
px[i]=i;
qsort(px+1,m,sizeof(int),cmp);
for(int i=1;i<=m;i++)
wz[px[i]]=i;
jianshu(1,1,m+1);
for(int i=1;i<=m;i++)
{
int jg=getans(m,wz[i]);
if(xk[i]<jg)
jg=xk[i];
xiugai(m,wz[i],jg);
printf("%d\n",jg);
}
return 0;
}

模拟赛 怨灵退治 题解(Hall定理+线段树)的更多相关文章

  1. loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树

    题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...

  2. 【BZOJ2138】stone Hall定理+线段树

    [BZOJ2138]stone Description 话说Nan在海边等人,预计还要等上M分钟.为了打发时间,他玩起了石子.Nan搬来了N堆石子,编号为1到N,每堆包含Ai颗石子.每1分钟,Nan会 ...

  3. ARC076 F Exhausted? Hall定理 + 线段树扫描线

    ---题面--- 题目大意: 有n个人,m个座位,每个人可以匹配的座位是[1, li] || [ri, m],可能有人不需要匹配座位(默认满足),问最少有多少人不能被满足. 题解: 首先可以看出这是一 ...

  4. BZOJ3693: 圆桌会议(Hall定理 线段树)

    题意 题目链接 Sol 好的又是神仙题... 我的思路:对于区间分两种情况讨论,一种是完全包含,另一种是部分包含.第一种情况非常好判断,至于计算对于一个区间[l, r]的$\sum a[i]$就可以了 ...

  5. BZOJ.3693.圆桌会议(Hall定理 线段树)

    题目链接 先考虑链.题目相当于求是否存在完备匹配.那么由Hall定理,对于任意一个区间[L,R],都要满足[li,ri]完全在[L,R]中的ai之和sum小于等于总位置数,即R-L+1.(其实用不到H ...

  6. LOJ.6062.[2017山东一轮集训]Pair(Hall定理 线段树)

    题目链接 首先Bi之间的大小关系没用,先对它排序,假设从小到大排 那么每个Ai所能匹配的Bi就是一个B[]的后缀 把一个B[]后缀的匹配看做一条边的覆盖,设Xi为Bi被覆盖的次数 容易想到 对于每个i ...

  7. BZOJ1135 LYZ(POI2009) Hall定理+线段树

    做这个题之前首先要了解判定二分图有没有完备匹配的Hall定理: 那么根据Hell定理,如果任何一个X子集都能连大于等于|S|的Y子集就可以获得完备匹配,那么就是: 题目变成只要不满足上面这个条件就能得 ...

  8. Codeforces 338E - Optimize!(Hall 定理+线段树)

    题面传送门 首先 \(b_i\) 的顺序肯定不会影响匹配,故我们可以直接将 \(b\) 数组从小到大排个序. 我们考虑分析一下什么样的长度为 \(m\) 的数组 \(a_1,a_2,\dots,a_m ...

  9. 计蒜客模拟赛 #5 (B 题) 动态点分治+线段树

    虽然是裸的换根dp,但是为了在联赛前锻炼码力,强行上了点分树+线段树. 写完+调完总共花了不到 $50$ 分钟,感觉还行. code: #include <bits/stdc++.h> # ...

随机推荐

  1. python基础 — 异常处理

    什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常. 异常是Python对象,表示一个错误. 当Pyth ...

  2. shell中if条件字符串、数字比对,[[ ]]和[ ]区别

    目录 shell 括号 test 和 []符号 [[]] 符号 let和(())符号 "[]" , "[[]]" 和 "(())"对比 sh ...

  3. Dubbo快速入门 五

    5. Dubbo注解版 之前在dubbo配置文件显式编写内容提供者和消费者,官方还提供了了一种注解方式,接下来改造项目 1.服务提供方 dubbo配置文件 将之前手动申明注释掉,添加<dubbo ...

  4. docker 入坑1

    本文是记录一下学习docker的过程,希望可以帮助到入门的朋友. 系统:ubuntu16.04 docker:18.09 打开官网:https://docs.docker.com/install/li ...

  5. IIS配置文件的XML格式不正确 applicationHost.config崩溃

    错误提示如图: 检查C:\Windows\System32\inetsrv\config目录下的applicationHost.config文件,备份一份. 可使用IIS提供的AppCmd.exe的r ...

  6. (二) Windows 进行 Docker CE 安装(Docker Desktop)

    参考并感谢 官方文档: https://docs.docker.com/docker-for-windows/install/ 下载地址 https://download.docker.com/win ...

  7. 并发编程-线程-死锁现象-GIL全局锁-线程池

    一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...

  8. css设置全局变量和局部变量

    在我们使用less或者sass时常常会使用到局部变量和全局变量,其实在我们使用css做开发时也可以定义全局变量和局部 变量来简化我们的开发效率,很简单也很实用:1.设置全局变量只需要在我们的根引用的c ...

  9. linux对象系统---kobject, ktype, kset, subsys

    本文转自:linux中kobject/ktype/kset/subsys之间的关系 随着内核版本的发展,会有一些变化,无论怎样,变化的是形式,不变的是思想! 那么他们之间具有什么关系?那应该不是'小3 ...

  10. python 版本号比较 重载运算符

    # -*- coding: utf-8 -*- class VersionNum(object): """ 版本号比较 默认版本以“.”分割,各位版本位数不超过3 例一: ...