[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 ...
随机推荐
- 0x28 IDA*
一个早上做完了我真牛B 就是A*用于DFS啊,现在我才发现迭代加深真是个好东西. poj3460 %了%了我们的目标是把它的顺序变对,那么第i个位置的值+1是要等于第i+1个位置的值的.对于一个操作, ...
- c语言循环案例
do while #include <stdio.h> #include <stdlib.h> int main() { int a = 1,b = 10; do { b -= ...
- POJ 1471 模拟?
题意:求最大无坏点三角形 思路: 模拟? (为什么我模拟过了...) 有人用 DP,有人用 搜索... // by SiriusRen #include <cstdio> #include ...
- C#学习小记
1.C#是由微软推出的,基于.Net Framework的面向对象的高级编程语言. 2.C#代码编辑器为Visual Studio,简称VS. 3.Hello World VS中新建Windows控制 ...
- struts2学习之基础笔记7
第十二章 Struts 2的标记库 1 OGNL简介 Object-Grephic Navigtor Language 图对象导航语言 作用:图对象导航语言是Struts 2标记库中为其相应标记属性进 ...
- 用replaceState操作路由的方法封装
export class Router { ReplaceState(url, data) { var query = this.Generate(data); window.history.repl ...
- 利用Windows2003 IP安全策略实现服务器远程桌面端口(3389)访问控制
1 开始 → 运行 → 对话框中输入gpedit.msc → 确定 2 打开“组策略编辑器” 计算机配置 → Windows配置 → 右键点击“IP安全策略,在 本地计算机” →选择“创建IP安全策略 ...
- Unity 默认进入的scenes
1,如果有多个场景,那么第一个场景要放在最上边,(其他的也要加) 2,如果不添加,那么Unity会把当前打开的场景添加进来. 3,切换场景的代码 using UnityEngine.SceneMana ...
- ABBYY迎国庆·庆中秋限时折扣狂潮,再来一波
继ABBYY 早秋限时活动之后,ABBYY官方为迎国庆,庆中秋,折扣狂潮,又来一波.上次活动由于时间短,任务急,数量少,使得不少小伙伴抱憾而止,选择默默等待良机.现在,良机来了,即便没有上次的打折力度 ...
- 树、递归、广度优先搜索(BFS)————二叉树的最小深度
解法一:递归 遇到叶子节点不递归,否则接着往子树递归,每次递归层数加1 要确定的是,一定要保证初始输入的节点是有子节点的.因为可能出现只有单子树的情况,所以要先确认这种情况. 具体过程: 1.分析初始 ...