【CF573D】Bear and Cavalry 线段树
【CF573D】Bear and Cavalry
题意:有n个人和n匹马,第i个人对应第i匹马。第i个人能力值ai,第i匹马能力值bi,第i个人骑第j匹马的总能力值为ai*bj,整个军队的总能力值为$\sum a_ib_j$(一个人只能骑一匹马,一匹马只能被一个人骑)。有一个要求:每个人都不能骑自己对应的马。让你制定骑马方案,使得整个军队的总能力值最大。现在有q个操作,每次给出a,b,交换a和b对应的马。每次操作后你都需要输出最大的总能力值。
$n\le 30000,q\le 10000$
题解:如果不考虑人不能骑自己的马这个限制的话,将人和马都按能力值从大到小排序后,肯定是能力值最大的人骑能力值最大的马,以此类推。但如果考虑这个限制,就有一个很神的结论:如果排名第i的人对应排名第j的马,则|i-j|<3(不会证,可以看官方题解)。
那么就有了一个比较基础的DP解法。令f[i]表示前i个人对应前i匹马的最大值,则f[i]有这几种转移:
i对应i
i对应i-1,i-1对应i
i对应i-1,i-1对应i-2,i-2对应i
i对应i-2,i-2对应i-1,i-1对应i
如果带修改,我们用线段树来维护,令f[i][a][b]表示i这个节点,左边a个没取,右边b个没取时的最大值。合并时细节比较多。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=30010;
typedef long long ll;
int n,m;
ll A[maxn],B[maxn],emp[3][3];
int ban[maxn],ra[maxn],rb[maxn];
struct node
{
int a,b;
}pa[maxn],pb[maxn];
struct M
{
ll v[3][3];
int l,r;
M operator + (const M &a) const
{
M b;
b.l=l,b.r=a.r;
int i,j;
for(i=0;i<3;i++) for(j=0;j<3;j++)
{
if(l+i==a.r-j+1)
{
b.v[i][j]=0;
continue;
}
if(l+i>a.r-j+1)
{
b.v[i][j]=-(1ll<<60);
continue;
}
if(r-l+1<i)
{
b.v[i][j]=a.v[i][i-(r-l+1)];
}
if(a.r-a.l+1<j)
{
b.v[i][j]=v[i][j-(a.r-a.l+1)];
continue;
}
int x=r,y=a.l;
b.v[i][j]=v[i][0]+a.v[0][j];
if(ban[x]!=y&&ban[y]!=x) b.v[i][j]=max(b.v[i][j],v[i][1]+a.v[1][j]+A[x]*B[y]+B[x]*A[y]);
if(ban[x]!=y&&ban[y]!=y+1&&ban[y+1]!=x) b.v[i][j]=max(b.v[i][j],v[i][1]+a.v[2][j]+A[x]*B[y]+A[y]*B[y+1]+A[y+1]*B[x]);
if(ban[x]!=y+1&&ban[y]!=x&&ban[y+1]!=y) b.v[i][j]=max(b.v[i][j],v[i][1]+a.v[2][j]+A[x]*B[y+1]+A[y]*B[x]+A[y+1]*B[y]);
if(ban[x-1]!=x&&ban[x]!=y&&ban[y]!=x-1) b.v[i][j]=max(b.v[i][j],v[i][2]+a.v[1][j]+A[x-1]*B[x]+A[x]*B[y]+A[y]*B[x-1]);
if(ban[x-1]!=y&&ban[x]!=x-1&&ban[y]!=x) b.v[i][j]=max(b.v[i][j],v[i][2]+a.v[1][j]+A[x-1]*B[y]+A[x]*B[x-1]+A[y]*B[x]);
}
return b;
}
}s[maxn<<2]; bool cmp(const node &a,const node &b)
{
return (a.a==b.a)?(a.b>b.b):(a.a>b.a);
}
void build(int l,int r,int x)
{
if(l==r)
{
memcpy(s[x].v,emp,sizeof(emp));
s[x].v[0][1]=s[x].v[1][0]=0,s[x].l=s[x].r=l;
if(ban[l]!=l) s[x].v[0][0]=A[l]*B[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a)
{
if(l==r)
{
memcpy(s[x].v,emp,sizeof(emp));
s[x].v[0][1]=s[x].v[1][0]=0,s[x].l=s[x].r=l;
if(ban[l]!=l) s[x].v[0][0]=A[l]*B[l];
return ;
}
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a);
else updata(mid+1,r,rson,a);
s[x]=s[lson]+s[rson];
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,a,b;
for(i=1;i<=n;i++) pa[i].a=rd(),pa[i].b=i;
for(i=1;i<=n;i++) pb[i].a=rd(),pb[i].b=i;
sort(pa+1,pa+n+1,cmp),sort(pb+1,pb+n+1,cmp);
for(i=1;i<=n;i++)
{
ra[pa[i].b]=i,rb[pb[i].b]=i,A[i]=pa[i].a,B[i]=pb[i].a;
}
for(i=1;i<=n;i++) ban[ra[i]]=rb[i];
for(a=0;a<3;a++) for(b=0;b<3;b++) emp[a][b]=-(1ll<<60);
//A[0]=B[0]=A[n+1]=B[n+1]=-(1ll<<60);
build(1,n,1);
for(i=1;i<=m;i++)
{
a=ra[rd()],b=ra[rd()];
swap(ban[a],ban[b]);
updata(1,n,1,a),updata(1,n,1,b);
printf("%lld\n",s[1].v[0][0]);
}
return 0;
}//4 3 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 3 4 3 2 4 3
【CF573D】Bear and Cavalry 线段树的更多相关文章
- Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)
Codeforces 题目传送门 & 洛谷题目传送门 这个 \(42\) 的条件非常奇怪,不过注意到本题 \(a_i\) 范围的最大值为 \(10^{14}\),而在值域范围内 \(42\) ...
- CH Round #52 还教室[线段树 方差]
还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教 ...
- Codeforces Round #305 (Div. 2) D题 (线段树+RMQ)
D. Mike and Feet time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- zjnu1762 U (线段树)
Description Mirko is hungry as a bear, scratch that, programmer and has stumbled upon a local restau ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- codevs 1082 线段树练习 3(区间维护)
codevs 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...
- codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...
- codevs 1080 线段树点修改
先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...
- codevs 1082 线段树区间求和
codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...
随机推荐
- Go学习入门
1. 为什么要学习Go Go语言宣称为互联网时代的C语言,那她有那些特性值得我们必须学习呢: 并行与分布式支持.除了我们日常熟悉的进程和线程,Go语言中提供了协程coroutine,从而简化了并行开发 ...
- [算法导论]插入排序 @ Python
class insertionsort(): def insertion_sort(self,Array): for i in range(1, len(Array)): key = Array[i] ...
- python3简单使用requests 用户代理,cookie池
官方文档:http://docs.python-requests.org/en/master/ 参考文档:http://www.cnblogs.com/zhaof/p/6915127.html#und ...
- sed 多行处理详细总结
在正常情况下,sed将待处理的行读入模式空间,脚本中的命令就一条接着一条的对该行进行处理,直到脚本执行完毕,然后该行被输出,模式空间请空:然后重复刚才的动作,文件中的新的一行被读入,直到文件处理完备. ...
- SpringBoot使用Mybatis注解开发教程-分页-动态sql
代码示例可以参考个人GitHub项目kingboy-springboot-data 一.环境配置 1.引入mybatis依赖 compile( //SpringMVC 'org.springframe ...
- C# System.Collections.Queue
using System; using System.Collections; public class SamplesQueue { public static void Main() { // C ...
- python3用BeautifulSoup抓取id='xiaodeng',且正则包含‘elsie’的标签
# -*- coding:utf-8 -*- #python 2.7 #XiaoDeng #http://tieba.baidu.com/p/2460150866 #使用多个指定名字的参数可以同时过滤 ...
- Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
SpringBoot项目编译成功,启动报错 提示信息很明显,通过查看依赖关系,可以找到原因 导致这个问题的原因是因为,在 pom.xml 配置文件中,配置了数据连接技术 spring-boot-sta ...
- s3cmd用法总结
概述 S3是亚马逊AWS提供的简单存储服务(可以理解为有公网域名的大容量高可用存储) S3配合CloudFront服务可作为CDN使用,它提供多节点全球发布 安装 方法一: yum install s ...
- Linux深入理解Socket异常
在各种网络异常情况的背后,TCP是怎么处理的?又是怎样把处理结果反馈给上层应用的?本文就来讨论这个问题.分为两个场景来讨论 建立连接时的异常情况 1 正常情况下 经过三次握手,客户端连接成功,服务端有 ...