[Avito Code Challenge 2018 G] Magic multisets(线段树)
题目链接:http://codeforces.com/contest/981/problem/G
题目大意:
有n个初始为空的‘魔法’可重集,向一个‘可重集’加入元素时,若该元素未出现过,则将其加入;否则该可重集中所有元素的个数都会翻倍。
例如将$2$加入${1,3}$会得到${1,2,3}$,将$2$加入${1,2,3,3}$会得到${1,1,2,2,3,3,3,3}$.
$q$次操作,每次操作要么向一个区间内的所有可重集加入某个元素,要么询问一个区间内可重集的大小之和。
$n,q ≤ 2×10^5$
题解:
发现对于出现过该元素的区间就是区间乘,没有出现过的就是区间加
操作1我们先把$[l,r]$全部乘上2,再把之前已经出现过当前元素的区间乘上2的逆元再+1,最后合并一下左右区间就好了。合并大概就是保证这个操作时间复杂度的关键了,只是我也不知道怎么算
发现这样我们要维护每个元素出现的区间,同时支持方便的合并,我们开n个set就好了
正是做完这题我发现我竟然不会写区间乘法线段树
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<set>
#define pa pair<int,int>
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll; const int N=2e5+;
const int mod=;
ll n,q,inv;
ll sum[N<<],add[N<<],mul[N<<];
set <pa> st[N];
inline ll read()
{
char ch=getchar();
ll s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
ll qpow(ll a,ll b)
{
ll re=;
for (;b;b>>=,a=a*a%mod) if (b&) re=re*a%mod;
return re;
}
void build(int o,int l,int r)
{
mul[o]=;add[o]=sum[o]=;
if (l==r) return;
build(o<<,l,mid);
build(o<<|,mid+,r);
}
void pushup(int o,int l,int r)
{
//sum[o]=sum[o<<1]+sum[o<<1|1];
sum[o]=(sum[o<<]*mul[o<<]+add[o<<]*(mid-l+))%mod;
sum[o]=(sum[o]+sum[o<<|]*mul[o<<|]+add[o<<|]*(r-mid))%mod;
}
void pushdown(int o,int l,int r)
{
if (mul[o]!=)
{
ll p=mul[o];
mul[o]=;
//(sum[o<<1]*=p)%=mod;
//(sum[o<<1|1]*=p)%=mod;
(add[o<<]*=p)%=mod;
(add[o<<|]*=p)%=mod;
(mul[o<<]*=p)%=mod;
(mul[o<<|]*=p)%=mod;
}
if (add[o]!=)
{
ll p=add[o];
add[o]=;
// (sum[o<<1]+=p*(mid-l+1))%=mod;
// (sum[o<<1|1]+=p*(r-mid))%=mod;
(add[o<<]+=p)%=mod;
(add[o<<|]+=p)%=mod;
}
}
void update(int o,int l,int r,int x,int y,ll z,int flag)
{
if (l>=x&&r<=y)
{
if (flag==)
{
(mul[o]*=z)%=mod;
(add[o]*=z)%=mod;
// (sum[o]*=z)%=mod;
}
if (flag==)
{
(add[o]+=z)%=mod;
// (sum[o]+=(r-l+1)*z)%=mod;
}
return;
}
pushdown(o,l,r);
if (x<=mid) update(o<<,l,mid,x,y,z,flag);
if (y>mid) update(o<<|,mid+,r,x,y,z,flag);
pushup(o,l,r);
}
void merge(int x,int L,int R)
{
set<pa>::iterator it;
it=st[x].lower_bound(pa(L,L));
for (;it!=st[x].end();it++)
{
set<pa>::iterator lst=it;lst--;
int l=(*lst).second+;
int r=(*it).first-;
int upl=max(L,l);
int upr=min(R,r);
if (upr>=upl)
{
update(,,n,upl,upr,inv,);
update(,,n,upl,upr,,);
}
if ((*it).first>=R) break;
}
int mergeL=L,mergeR=R;
it=st[x].upper_bound(pa(L,L));it--;
if ((*it).second>=mergeL) mergeL=(*it).first;
it=st[x].upper_bound(pa(R,R));it--;
if ((*it).second>=mergeR) mergeR=(*it).second;
vector <pa> er;
it=st[x].lower_bound(pa(mergeL,mergeL));
for (;it!=st[x].end();it++)
{
pa e=*it;
if (e.first>=mergeL&&e.second<=mergeR) er.push_back(e);
else break;
}
for (int i=;i<er.size();i++) st[x].erase(er[i]);
st[x].insert(pa(mergeL,mergeR));
}
ll query(int o,int l,int r,int x,int y)
{
if (l>=x&&r<=y) return (sum[o]*mul[o]+add[o]*(r-l+))%mod;
// if (l>=x&&r<=y) return sum[o]%mod;
pushdown(o,l,r);
ll re=;
if (x<=mid) (re+=query(o<<,l,mid,x,y))%=mod;
if (y>mid) (re+=query(o<<|,mid+,r,x,y))%=mod;
pushup(o,l,r);
return re;
}
int main()
{
inv=qpow(,mod-);
//inv=(mod+1)/2;
n=read();q=read();
for (int i=;i<=n;i++)
{
st[i].insert(pa(,));
st[i].insert(pa(n+,n+));
}
build(,,n);
while (q--)
{
int opt=read();
if (opt==)
{
int l=read(),r=read(),z=read();
update(,,n,l,r,,);
merge(z,l,r);
}
if (opt==)
{
int l=read(),r=read();
printf("%lld\n",query(,,n,l,r));
}
}
return ;
}
[Avito Code Challenge 2018 G] Magic multisets(线段树)的更多相关文章
- Codeforces Avito Code Challenge 2018 D. Bookshelves
Codeforces Avito Code Challenge 2018 D. Bookshelves 题目连接: http://codeforces.com/contest/981/problem/ ...
- Codeforces - Avito Code Challenge 2018
Portal A. Antipalindrome 暴力. B. Businessmen Problems 暴力. C. Useful Decomposition 居然不是C打头的?! 将一棵树划分成若 ...
- Avito Code Challenge 2018 C
C. Useful Decomposition time limit per test 1 second memory limit per test 256 megabytes input stand ...
- Avito Code Challenge 2018 A~E
A. Antipalindrome 还以为是什么神dp结果就是分情况讨论啊 原串是一串一样的字符的话输出0,是回文串的话输出n-1,否则直接输出原串长度 #include<iostream> ...
- cf掉分记——Avito Code Challenge 2018
再次作死的打了一次cf的修仙比赛感觉有点迷.. 还好掉的分不多(原本就太低没法掉了QAQ) 把会做的前三道水题记录在这.. A: Antipalindrome emmmm...直接暴力枚举 code: ...
- Avito Code Challenge 2018
第一次打CF,很菜,A了三道水题,第四题好像是是数位DP,直接放弃了.rateing从初始的1500变成了1499,还是绿名,这就很尴尬.之后觉得后面的题目也没有想象的那么难(看通过人数)过两天吧剩下 ...
- BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流
BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流 Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1 ...
- ACM-ICPC 2018 徐州赛区网络预赛-G Trace(线段树的应用
Problem:Portal传送门 Problem:Portal传送门 原题目描述在最下面. 我理解的题意大概是:有n次涨潮和退潮,每次的范围是个x×y的矩形,求n次涨退潮后,潮水痕迹的长度. ...
- 【Codeforces717F】Heroes of Making Magic III 线段树 + 找规律
F. Heroes of Making Magic III time limit per test:3 seconds memory limit per test:256 megabytes inpu ...
随机推荐
- [jzoj 6101] [GDOI2019模拟2019.4.2] Path 解题报告 (期望)
题目链接: https://jzoj.net/senior/#main/show/6101 题目: 题解: 设$f_i$表示从节点$i$到节点$n$的期望时间,$f_n=0$ 最优策略就是如果从$i, ...
- oracle (9I/10G/11G)数据库日志挖掘(审计误操作)
文档结构: 资料来自官方网站: https://docs.oracle.com/cd/E11882_01/server.112/e22490/logminer.htm#SUTIL019 来自论坛: h ...
- Spark SQL概念学习系列之用户自定义函数
不多说,直接上干货! 用户自定义函数 注册udf 我们可以使用Spark 支持的编程语言编写好函数,然后通过Spark SQL 内建的方法传递进来,非常便捷地注册我们自己的UDF 在Scala 和Py ...
- synchronized同步机制,修饰类和修饰对象的区别
synchronized用法 synchronized修饰的对象有几种: 修饰一个类:其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象: 修饰一个方法:被修饰的 ...
- sql获得某个时间段的数据
CONVERT(Date, 时间字符串变量 ) between CONVERT(Date,'2015/2/10') and CONVERT(Date,'2015-3-10')
- luogu p1003
P1003 题意 经过多个矩形(1e3)覆盖后后某个坐标属于那个矩形(仅仅是一次询问) 大水题,直接的做法,从后向前处理矩形是否覆盖查询的点,若覆盖,则是该矩形编号 题解 int get_num(){ ...
- linux防火墙查看状态firewall、iptable
一.iptables防火墙1.基本操作 # 查看防火墙状态 service iptables status # 停止防火墙 service iptables stop # 启动防火墙 service ...
- 改变浏览器页面默认滚动条样式scrollbar
scrollbar-3d-light-color 设置或检索滚动条亮边框颜色scrollbar-highlight-color 设置或检索滚动条3D界面的亮边(ThreedHighlight)颜色sc ...
- JS侧边栏实现
<!DOCTYPE html> <html lang="en"> <style> </style> <head> < ...
- 常用js方法封装
常用js方法封装 var myJs = { /* * 格式化日期 * @param dt 日期对象 * @returns {string} 返回值是格式化的字符串日期 */ getDates: fun ...