题目链接: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(线段树)的更多相关文章

  1. Codeforces Avito Code Challenge 2018 D. Bookshelves

    Codeforces Avito Code Challenge 2018 D. Bookshelves 题目连接: http://codeforces.com/contest/981/problem/ ...

  2. Codeforces - Avito Code Challenge 2018

    Portal A. Antipalindrome 暴力. B. Businessmen Problems 暴力. C. Useful Decomposition 居然不是C打头的?! 将一棵树划分成若 ...

  3. Avito Code Challenge 2018 C

    C. Useful Decomposition time limit per test 1 second memory limit per test 256 megabytes input stand ...

  4. Avito Code Challenge 2018 A~E

    A. Antipalindrome 还以为是什么神dp结果就是分情况讨论啊 原串是一串一样的字符的话输出0,是回文串的话输出n-1,否则直接输出原串长度 #include<iostream> ...

  5. cf掉分记——Avito Code Challenge 2018

    再次作死的打了一次cf的修仙比赛感觉有点迷.. 还好掉的分不多(原本就太低没法掉了QAQ) 把会做的前三道水题记录在这.. A: Antipalindrome emmmm...直接暴力枚举 code: ...

  6. Avito Code Challenge 2018

    第一次打CF,很菜,A了三道水题,第四题好像是是数位DP,直接放弃了.rateing从初始的1500变成了1499,还是绿名,这就很尴尬.之后觉得后面的题目也没有想象的那么难(看通过人数)过两天吧剩下 ...

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

  8. ACM-ICPC 2018 徐州赛区网络预赛-G Trace(线段树的应用

    Problem:Portal传送门 Problem:Portal传送门  原题目描述在最下面.  我理解的题意大概是:有n次涨潮和退潮,每次的范围是个x×y的矩形,求n次涨退潮后,潮水痕迹的长度.   ...

  9. 【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 ...

随机推荐

  1. angularjs1-4 事件指令

    <div ng-app="myApp"> <div ng-controller="firstController"> <div n ...

  2. h5-登录

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  3. Swift 实践之UIWebView

    1.选中工程,点击右键,New File>在iOS下选中Othe>Empty,生成一个.js的脚本文件,将代码粘贴过去保存; var script = document.createEle ...

  4. hdoj--3440--House Man(差分约束)

    House Man Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  5. nyoj--68--三点顺序(数学)

    三点顺序 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 现在给你不共线的三个点A,B,C的坐标,它们一定能组成一个三角形,现在让你判断A,B,C是顺时针给出的还是逆时针 ...

  6. caffe study- AlexNet 之算法篇

    在机器学习中,我们通常要考虑的一个问题是如何的“以偏概全”,也就是以有限的样本或者结构去尽可能的逼近全局的分布.这就要在样本以及结构模型上下一些工夫. 在一般的训练任务中,考虑的关键问题之一就是数据分 ...

  7. Spring《二》 Bean的生命周期

    Bean初始化 1.bean中实现public void init():方法,config.xml中增加init-method="init" 属性. 2.bean实现接口Initi ...

  8. SQL Server 分割字符串转列

    CREATE FUNCTION dbo.sf_DS_SplitNVarchar ( @strValues nvarchar(4000) ) RETURNS @tblStrList TABLE (id ...

  9. mysql学习 2

    1.建立外键 create table <表名>( <字段> 字段类型 not null, <字段> 字段类型 not null, <字段> 字段类型 ...

  10. js判断传入时间和当前时间大小

    //判断时间是否过期 function judgeTime(time){ var strtime = time.replace("/-/g", "/");//时 ...