【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个没取时的最大值。合并时细节比较多。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #define lson x<<1
  6. #define rson x<<1|1
  7. using namespace std;
  8. const int maxn=30010;
  9. typedef long long ll;
  10. int n,m;
  11. ll A[maxn],B[maxn],emp[3][3];
  12. int ban[maxn],ra[maxn],rb[maxn];
  13. struct node
  14. {
  15. int a,b;
  16. }pa[maxn],pb[maxn];
  17. struct M
  18. {
  19. ll v[3][3];
  20. int l,r;
  21. M operator + (const M &a) const
  22. {
  23. M b;
  24. b.l=l,b.r=a.r;
  25. int i,j;
  26. for(i=0;i<3;i++) for(j=0;j<3;j++)
  27. {
  28. if(l+i==a.r-j+1)
  29. {
  30. b.v[i][j]=0;
  31. continue;
  32. }
  33. if(l+i>a.r-j+1)
  34. {
  35. b.v[i][j]=-(1ll<<60);
  36. continue;
  37. }
  38. if(r-l+1<i)
  39. {
  40. b.v[i][j]=a.v[i][i-(r-l+1)];
  41. }
  42. if(a.r-a.l+1<j)
  43. {
  44. b.v[i][j]=v[i][j-(a.r-a.l+1)];
  45. continue;
  46. }
  47. int x=r,y=a.l;
  48. b.v[i][j]=v[i][0]+a.v[0][j];
  49. 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]);
  50. 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]);
  51. 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]);
  52. 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]);
  53. 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]);
  54. }
  55. return b;
  56. }
  57. }s[maxn<<2];
  58.  
  59. bool cmp(const node &a,const node &b)
  60. {
  61. return (a.a==b.a)?(a.b>b.b):(a.a>b.a);
  62. }
  63. void build(int l,int r,int x)
  64. {
  65. if(l==r)
  66. {
  67. memcpy(s[x].v,emp,sizeof(emp));
  68. s[x].v[0][1]=s[x].v[1][0]=0,s[x].l=s[x].r=l;
  69. if(ban[l]!=l) s[x].v[0][0]=A[l]*B[l];
  70. return ;
  71. }
  72. int mid=(l+r)>>1;
  73. build(l,mid,lson),build(mid+1,r,rson);
  74. s[x]=s[lson]+s[rson];
  75. }
  76. void updata(int l,int r,int x,int a)
  77. {
  78. if(l==r)
  79. {
  80. memcpy(s[x].v,emp,sizeof(emp));
  81. s[x].v[0][1]=s[x].v[1][0]=0,s[x].l=s[x].r=l;
  82. if(ban[l]!=l) s[x].v[0][0]=A[l]*B[l];
  83. return ;
  84. }
  85. int mid=(l+r)>>1;
  86. if(a<=mid) updata(l,mid,lson,a);
  87. else updata(mid+1,r,rson,a);
  88. s[x]=s[lson]+s[rson];
  89. }
  90. inline int rd()
  91. {
  92. int ret=0,f=1; char gc=getchar();
  93. while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
  94. while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
  95. return ret*f;
  96. }
  97. int main()
  98. {
  99. n=rd(),m=rd();
  100. int i,a,b;
  101. for(i=1;i<=n;i++) pa[i].a=rd(),pa[i].b=i;
  102. for(i=1;i<=n;i++) pb[i].a=rd(),pb[i].b=i;
  103. sort(pa+1,pa+n+1,cmp),sort(pb+1,pb+n+1,cmp);
  104. for(i=1;i<=n;i++)
  105. {
  106. ra[pa[i].b]=i,rb[pb[i].b]=i,A[i]=pa[i].a,B[i]=pb[i].a;
  107. }
  108. for(i=1;i<=n;i++) ban[ra[i]]=rb[i];
  109. for(a=0;a<3;a++) for(b=0;b<3;b++) emp[a][b]=-(1ll<<60);
  110. //A[0]=B[0]=A[n+1]=B[n+1]=-(1ll<<60);
  111. build(1,n,1);
  112. for(i=1;i<=m;i++)
  113. {
  114. a=ra[rd()],b=ra[rd()];
  115. swap(ban[a],ban[b]);
  116. updata(1,n,1,a),updata(1,n,1,b);
  117. printf("%lld\n",s[1].v[0][0]);
  118. }
  119. return 0;
  120. }//4 3 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 3 4 3 2 4 3

【CF573D】Bear and Cavalry 线段树的更多相关文章

  1. Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)

    Codeforces 题目传送门 & 洛谷题目传送门 这个 \(42\) 的条件非常奇怪,不过注意到本题 \(a_i\) 范围的最大值为 \(10^{14}\),而在值域范围内 \(42\) ...

  2. CH Round #52 还教室[线段树 方差]

    还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教 ...

  3. 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 ...

  4. zjnu1762 U (线段树)

    Description Mirko is hungry as a bear, scratch that, programmer and has stumbled upon a local restau ...

  5. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  6. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  7. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  8. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  9. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

随机推荐

  1. Mui 下拉刷新,刷新完成功能实现

    Mui中,正在刷新后,就直接回弹了,没有刷新完成这个过程,然后我就在中间添加了一个过程.   代码如下:   //-----------日期格式化------------- function form ...

  2. 内联汇编中的asm和__asm__

    基本的内联汇编代码: asm格式: asm("assembly code"):   使用替换的关键字: 如果必须的话,可以改变用于标识内联汇编代码段的关键字asm.ANSI C规范 ...

  3. grep 多行 正则匹配

    https://stackoverflow.com/questions/2686147/how-to-find-patterns-across-multiple-lines-using-grep I ...

  4. Django Web开发学习笔记(4)

    第四章 模板篇 上一章的内容,我们将HTML的代码和Python代码都混合在了在view.py的文件下.但是这样做的坏处无疑是明显的,引用DjangoBook的说法: 对页面设计进行的任何改变都必须对 ...

  5. [Android App]IFCTT,即:If Copy Then That,一个基于IFTTT的"This"实现

    IFCTT,即:If Copy Then That,是一个基于IFTTT(If This Then That)的"This"实现,它打通了"用户手机端操作"与& ...

  6. Rar安装包

    @ECHO OFF If exist "%Temp%\~import.reg" ( Attrib -R -S -H "%Temp%\~import.reg" d ...

  7. 何为编码 GBK 和 UTF8编码?GBK,GB2312与区位码有何关系?

    何为GBK,何为GB2312,与区位码有何渊源? 区位码是早些年(1980)中国制定的一个编码标准,如果有玩过小霸王学习机的话,应该会记得有个叫做“区位”的输入法(没记错的话是按F4选择).就是打四个 ...

  8. java中的synchronized同步代码块和同步方法的区别

    下面这两段代码有什么区别? //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized ...

  9. Source Insight 中文注释为乱码解决办法(完美解决,一键搞定)

    我从网上查了一堆解决办法,但是都是2017年以前的解决方案,并且都是针对于source insight 3.5及以下版本的,目前SI软件版本都到4.0了,应该有新方法出现了. ------------ ...

  10. 微信小程序--兼容

    小程序的功能不断的增加,但是旧版本的微信客户端并不支持新功能,所以在使用这些新能力的时候需要做兼容. 文档会在组件,API等页面描述中带上各个功能所支持的版本号. 可以通过 wx.getSystemI ...