hdu5737
首先思考一个朴素的做法
将b[]维护成一个线段树套有序表,每次修改a[]用线段树+lazy tag
并在线段树的子区间上在有序表中二分更新这段区间中a[i]>=b[i]的值,复杂度O(nlog^2)
有没有更优的做法?
考虑在一次修改操作中,查询的数是相同的,并且b[]这个有序表始终不变
因此在生成b[]的线段树套有序表过程中(其实就是归并排序的记录)
我们维护每个数在左右子区间中名次。
这样修改的时候我们只要对b[]排好序的整体做一次二分,找到b[m]<=x<b[m+1]
把修改成x当作修改成b[m],这样我们就能O(1)地更新每个子区间的计数,问题得解
#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
const int mo=;
vector< pair<int,int> > tr[*];
int laz[*],s[*],a[],b[],c[];
int A,B,n,m,t;
int C = ~(<<), M = (<<)-;
int rnd(int last,int &a,int &b)
{
a = ( + (last >> )) * (a & M) + (a >> );
b = ( + (last >> )) * (b & M) + (b >> );
return (C & ((a << ) + b)) % ;
} void build(int i,int l,int r)
{
laz[i]=-;
tr[i].clear();
if (l==r)
{
s[i]=(a[l]>=b[l]);
}
else {
int m=(l+r)>>;
build(i*,l,m);
build(i*+,m+,r);
s[i]=s[i*]+s[i*+];
int x=l,y=m+,h=l;
while (x<=m&&y<=r)
{
if (b[x]<b[y])
{
tr[i].push_back(mp(x-l,y-m-));
c[h++]=b[x++];
}
else {
tr[i].push_back(mp(x-l-,y-m-));
c[h++]=b[y++];
}
}
while (x<=m)
{
tr[i].push_back(mp(x-l,r-m-));
c[h++]=b[x++];
}
while (y<=r)
{
tr[i].push_back(mp(m-l,y-m-));
c[h++]=b[y++];
}
for (int k=l; k<=r; k++) b[k]=c[k];
}
} void push(int i)
{
int x=laz[i];
laz[i*]=(x==-)?-:tr[i][x].first;
laz[i*+]=(x==-)?-:tr[i][x].second;
s[i*]=laz[i*]+;
s[i*+]=laz[i*+]+;
laz[i]=-;
} void add(int i,int l,int r,int x,int y,int w)
{
if (x<=l&&y>=r)
{
laz[i]=w;
s[i]=w+;
}
else {
int m=(l+r)>>;
if (laz[i]>-) push(i);
if (x<=m) add(i*,l,m,x,y,w==-?w:tr[i][w].first);
if (y>m) add(i*+,m+,r,x,y,w==-?w:tr[i][w].second);
s[i]=s[i*]+s[i*+];
}
} int ask(int i,int l,int r,int x,int y)
{
if (x<=l&&y>=r) return s[i];
else {
int m=(l+r)>>,ans=;
if (laz[i]>-) push(i);
if (x<=m) ans+=ask(i*,l,m,x,y);
if (y>m) ans+=ask(i*+,m+,r,x,y);
return ans;
}
} int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%d%d%d%d",&n,&m,&A,&B);
for (int i=; i<=n; i++) scanf("%d",&a[i]);
for (int i=; i<=n; i++) scanf("%d",&b[i]);
b[n+]=;
build(,,n);
int ans=;
int last=;
for (int i=; i<=m; i++)
{
int l=rnd(last,A,B)%n+,r=rnd(last,A,B)%n+,x=rnd(last,A,B)+;
if (l>r) swap(l,r);
if ((l+r+x)%==)
{
last=ask(,,n,l,r);
ans=(ans+1ll*i*last%mo)%mo;
}
else {
int w=upper_bound(b+,b++n,x)-b-;
add(,,n,l,r,w);
}
}
printf("%d\n",ans);
}
}
hdu5737的更多相关文章
- hdu5737(2016多校联赛第2场D)
题意:给2组数据a和b数组,每次有2种操作:(+,l,r,x)把a数组第l个到第r个元素全置为x,(?,l,r)查询[l,r]之间哪些位置满足a[i]>=b[i](i>=l &&a ...
- HDU5737 : Differencia
注意到$b$不变,考虑用归并树来维护这个$b$序列,对于每个节点有序地维护$b$,同时在归并的时候预处理出每个元素在左右儿子里的排名. 在归并树上额外维护区间内$a\geq b$的个数以及赋值标记. ...
随机推荐
- HDU B-Ignatius and the Princess IV
http://acm.hdu.edu.cn/showproblem.php?pid=1029 Problem Description "OK, you are not too bad, em ...
- 【Python】- 如何使用Visual Studio 2013编写python?
安装Visual Studio 2013 1.VS2013下载安装略 安装python2.7 1.从官网下载python2.7,下载地址:https://www.python.org/getit/ ...
- BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)
看到比值先二分答案.于是转化成一个非常裸的树形背包.直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对.这里使用一种更通用的dfs序优化树形背包写法.https://www.cnb ...
- BZOJ3073 PA2011Journeys(线段树+bfs)
线段树优化建图裸题.建两棵线段树,一棵表示入一棵表示出.对题中所给的边新建一个虚拟点,将两段区间拆成线段树上对应区间,出线段树中对应区间所表示的点向虚拟点连边权0的边,虚拟点向入线段树中对应区间所表示 ...
- P1531 I Hate It
题目背景 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 题目描述 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的 ...
- 【算法】CDQ分治 -- 三维偏序 & 动态逆序对
初次接触CDQ分治,感觉真的挺厉害的.整体思路即分而治之,再用之前处理出来的答案统计之后的答案. 大概流程是(对于区间 l ~ r): 1.处理 l ~mid, mid + 1 ~ r 的答案: 2. ...
- [洛谷P1747]好奇怪的游戏
题目大意:有两匹马,马可以走"日",也可以像象走"田",求它走到(1,1)的步数. 题解:bfs 卡点:边界判断成了可以走到(0,y)或(x,0) C++ Co ...
- GYM - 100814 C.Connecting Graph
题意: 初始有n个点,m次操作.每次操作加一条边或者询问两个点第一次连通的时刻(若不连通输出-1). 题解: 用并查集维护每个点所在连通块的根.对于每次加边,暴力的更新新的根. 每次将2个块合并时,将 ...
- BZOJ1143 [CTSC2008]祭祀river 【二分图匹配】
1143: [CTSC2008]祭祀river Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3236 Solved: 1651 [Submit] ...
- 获取Parameter参数值,方便调试使用
#region #warning 调试使用,获取sql参数化,拼接出完整的sql语句,复制sql明文到mssql中运行 string debugSql = queryHelper.CommandTex ...