【HMOI】小C的填数游戏 DP+线段树维护
【题目描述】
一个长为n的序列,每个元素有一个a[i],b[i],a[i]为0||1,每个点和他相邻的两个点分别有两条边,权值为cost1[i],cost2[i],对于每个区间l,r,我们可以给每一个数一个c[i]值,c[i]=0||1,使得Σ(b[j]*(a[j]^c[j]))+cost1[j]*(c[j]^c[j+1])+cost2[j]*(c[j]^c[j+2]),j,j+1,j+2在[l,r]内时累加,现在有m次操作:
M x:将x位置的a[i]^=1;
Q l r:询问区间l,r的答案。
首先假设询问的只是一个区间,那么我们可以比较容易的用dp来求解w[i][s]表示到第i位的时候,后两位选的s的最小值,那么我们可以转移到w[i+1][ss]。这样就可以得到答案了。
但是现在我们支持区间询问和修改,所以我们用线段树来维护,每个节点记录w[s],s为这个区间左面两个点c[i]的选取方法和右面两个点的选取方法,那么只要我们可以维护线段树每个节点的w[i],我们就可以解决这个问题了。
对于合并操作比较简单,只需要枚举两个节点的s,然后更新的ss就可以了。
反思:一个节点的情况需要特殊处理,开始没注意到这个,后来改了半天,合并的时候还分了三种情况讨论= =。
还需要开LL,设inf的时候设的是#define inf (1<<60) 结果改了半天= =
评测数据的5号评测点少了一个操作,然后我的输出就多了一行= =。
//By BLADEVIL
#include <cstdio>
#include <cstring>
#define min(x,y) (x>y)?y:x;
#define inf (1ll<<60)
#define maxn 30010
#define LL long long using namespace std; struct rec {
int left,right;
LL key;
LL w[];
rec() {
left=right=;
key=inf;
for (LL i=;i<;i++) w[i]=inf;
}
}t[maxn<<]; LL n,m;
LL a[maxn],b[maxn],cost1[maxn],cost2[maxn];
char s[]; void init(int x) {
t[x].w[]=b[t[x].left]*a[t[x].left];
t[x].w[]=b[t[x].left]*(a[t[x].left]^);
t[x].key=min(t[x].w[],t[x].w[]);
} rec update(rec a,rec b) {
rec ans;
ans.left=a.left; ans.right=b.right;
if ((a.left==a.right)&&(b.left==b.right))
for (LL s=;s<;s++) {
LL ss=s|(s<<);
LL c1=((s&)==)?:,c2=((s&)==)?:;
//if ((ss==3)&&(a.left==1)) printf("%d %d\n",c1,c2);
if ((a.w[c1]==inf)||(b.w[c2]==inf)) continue;
ans.w[ss]=min(ans.w[ss],a.w[c1]+b.w[c2]+(c1^c2)*cost1[a.right]);
//if ((ss==3)&&(a.left==1)&&(a.right==1)) printf("%d\n",ans.w[ss]);
ans.key=min(ans.key,ans.w[ss]);
//if ((a.left==1)&&(a.right==1)) printf("%d %d\n",ans.key,ss);
} else
if (a.left==a.right)
for (LL s1=;s1<;s1++)
for (LL s2=;s2<;s2++) {
if ((a.w[s1]==inf)||(b.w[s2]==inf)) continue;
LL s=;
s|=s1<<; s|=(s2&)>>; s|=s2&;
LL c2=((s2&)==)?:,c3=((s2&)==)?:;
ans.w[s]=min(ans.w[s],a.w[s1]+b.w[s2]+(s1^c2)*cost1[a.left]+(s1^c3)*cost2[a.left]);
ans.key=min(ans.key,ans.w[s]);
} else
if (b.left==b.right)
for (LL s1=;s1<;s1++)
for (LL s2=;s2<;s2++) {
if ((a.w[s1]==inf)||(b.w[s2]==inf)) continue;
LL s=;
s|=s2; s|=(s1&)<<; s|=s1&;
LL c1=((s1&)==)?:,c2=((s1&)==)?:;
ans.w[s]=min(ans.w[s],a.w[s1]+b.w[s2]+(c1^s2)*cost2[a.right-]+(c2^s2)*cost1[a.right]);
ans.key=min(ans.key,ans.w[s]);
} else
if ((a.left!=a.right)&&(b.left!=b.right))
for (LL s1=;s1<;s1++)
for (LL s2=;s2<;s2++) {
if ((a.w[s1]==inf)||(b.w[s2])==inf) continue;
LL s=(s1>>)<<;
s|=s2&;
LL c1=((s1&)==)?:,c2=((s1&)==)?:;
LL c3=((s2&)==)?:,c4=((s2&)==)?:;
LL Ans=a.w[s1]+b.w[s2];
Ans+=cost1[a.right]*(c2^c3)+cost2[a.right]*(c2^c4)+cost2[a.right-]*(c1^c3);
ans.w[s]=min(ans.w[s],Ans);
ans.key=min(ans.key,ans.w[s]);
}
return ans;
} void build(int x,int l,int r) {
t[x].left=l; t[x].right=r;
if (t[x].left==t[x].right) {
init(x);
return ;
}
int mid=l+r>>;
build(x<<,l,mid); build((x<<)+,mid+,r);
t[x]=update(t[x<<],t[(x<<)+]);
} rec query(int x,int l,int r) {
if ((t[x].left==l)&&(t[x].right==r)) return t[x];
int mid=t[x].left+t[x].right>>;
if (mid>=r) return query(x<<,l,r); else
if (mid<l) return query((x<<)+,l,r); else
return update(query(x<<,l,mid),query((x<<)+,mid+,r));
} void change(int x,int y) {
if (t[x].left==t[x].right) {
init(x);
return ;
}
LL mid=t[x].left+t[x].right>>;
if (y>mid) change((x<<)+,y); else change(x<<,y);
t[x]=update(t[x<<],t[(x<<)+]);
} int main() {
freopen("game.in","r",stdin); freopen("game.out","w",stdout);
scanf("%lld%lld",&n,&m);
for (LL i=;i<=n;i++) scanf("%lld",&a[i]);
for (LL i=;i<=n;i++) scanf("%lld",&b[i]);
for (LL i=;i<n;i++) scanf("%lld",&cost1[i]);
for (LL i=;i<n-;i++) scanf("%lld",&cost2[i]);
build(,,n);
/*
for (LL s=0;s<16;s++) printf("%d %d\n",s,query(1,1,3).w[s]);
return 0;
*/
//printf("%d\n",query(1,2,4).key); return 0;
while (m--) {
scanf("%s",s);
LL x,y;
if (s[]=='Q') {
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(,x,y).key);
} else {
scanf("%lld",&x);
a[x]^=;
change(,x);
}
}
//for (LL s=0;s<16;s++) printf("%d %d\n",s,query(1,1,4).w[s]);
fclose(stdin); fclose(stdout);
return ;
}
【HMOI】小C的填数游戏 DP+线段树维护的更多相关文章
- 小C的填数游戏
题意: 给出一张n个点的无向图 i连向i-1和i-2 边权为wij 有两个点权ai和bi ai为0或1 在给m个操作 1.将ai异或1 2.将区间x到y的点都填上一个数ci 使得Σ(bi*(ai^ci ...
- Codeforces 834D The Bakery【dp+线段树维护+lazy】
D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...
- [动态dp]线段树维护转移矩阵
背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区 ...
- Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵
Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries ...
- bzoj 1594: [Usaco2008 Jan]猜数游戏——二分+线段树
Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,00 ...
- 【bzoj1594-猜数游戏】线段树
题解: 矛盾只有两种情况: 一.先前确定了x在区间(l,r),但是现在发现x在区间(l1,r1),并且两个区间不相交. 二.一个区间的最小值是x,这个区间中有一个子区间的最小值比x更小. 首先可以明确 ...
- DP+线段树维护矩阵(2019牛客暑期多校训练营(第二场))--MAZE
题意:https://ac.nowcoder.com/acm/contest/882/E 给你01矩阵,有两种操作:1是把一个位置0变1.1变0,2是问你从第一行i开始,到最后一行j有几种走法.你只能 ...
- Codeforces 833B 题解(DP+线段树)
题面 传送门:http://codeforces.com/problemset/problem/833/B B. The Bakery time limit per test2.5 seconds m ...
- @NOIP2018 - D2T2@ 填数游戏
目录 @题目描述@ @题解@ @代码@ @题目描述@ 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个 n×m 的矩形表格.玩家需要在表格的每个格子中填入一个数字(数字 ...
随机推荐
- ZOJ 1457 E-Prime Ring Problem
https://vjudge.net/contest/67836#problem/E A ring is compose of n circles as shown in diagram. Put n ...
- react项目开发入门
v16.2.0 在html头部引入react相关js文件 <!-- react核心库--><script src="../static/react/react.produc ...
- phpcms开启在线编辑模版 方法
目录:\caches\configs\system.php 将:第20行 'tpl_edit'=> 0 修改为 'tpl_edit'=> 1 (0:默认的,不开启: 1: ...
- VMbox复制虚拟机后网卡问题-bring up interface eth0:Device eth0 does not seem to be present
1.使用 ifconfig -a 查看mac地址 eg:HWaddr:08:00:29:B2:2B 2.vi /etc/sysconfig/network-scripts/ifcfg-eth0 将 ...
- Android OCR文字识别 实时扫描手机号(极速扫描单行文本方案)
身份证识别:https://github.com/wenchaosong/OCR_identify 遇到一个需求,要用手机扫描纸质面单,获取面单上的手机号,最后决定用tesseract这个开源OCR库 ...
- [C/C++] 结构体存储问题
64位操作系统,不同类型变量对应的字节数为: char : 1个字节 char*(即指针变量) : 8个字节 //32位占4个字节 short int : 2个字节 int : 4个字节 unsign ...
- 【bzoj3142】[Hnoi2013]数列 数学
题目描述 求满足 $1\le a_i\le n\ ,\ 1\le a_{i+1}-a_i\le m$ 的序列 $a_1...a_k$ 的个数模 $p$ 的值. 输入 只有一行用空格隔开的四个数:N.K ...
- Linux特殊字符含义
文件名以 ' . ' 开头的都是隐藏文件或目录,只需要在文件或目录名前添加 ' . ' 就可以隐藏它 ~ 表示主目录 . 当前目录 . . ...
- 未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出
安装微软的windows补丁 KB2781514 ,补丁主要解决“在 .NET Framework 4.5 更新之后,Visual Studio 用户可能无法打开或创建 C++ 或 JavaScrip ...
- 具体数学数论章-----致敬Kunth
整除性(divisible): 引入了代表整除性. m\n (m|n) 表示m整除n.注意这里的整除.表示的是n = km(k为整数). 在整除性这里.m必须是个正数.也许你可以描述n 是 m 的k倍 ...