[Avito Code Challenge 2018 G] Magic multisets(線段樹)

來源:互聯網
上載者:User

標籤:space   font   線段   namespace   tchar   ios   define   void   連結   

題目連結: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+15;const int mod=998244353;ll n,q,inv;ll sum[N<<2],add[N<<2],mul[N<<2];set <pa> st[N];  inline ll read(){    char ch=getchar();    ll s=0,f=1;    while (ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) f=-1;ch=getchar();}    while (ch>=‘0‘&&ch<=‘9‘) {s=(s<<3)+(s<<1)+ch-‘0‘;ch=getchar();}    return s*f;}ll qpow(ll a,ll b){    ll re=1;    for (;b;b>>=1,a=a*a%mod) if (b&1) re=re*a%mod;    return re;}void build(int o,int l,int r){    mul[o]=1;add[o]=sum[o]=0;    if (l==r) return;    build(o<<1,l,mid);    build(o<<1|1,mid+1,r);}void pushup(int o,int l,int r){    //sum[o]=sum[o<<1]+sum[o<<1|1];    sum[o]=(sum[o<<1]*mul[o<<1]+add[o<<1]*(mid-l+1))%mod;    sum[o]=(sum[o]+sum[o<<1|1]*mul[o<<1|1]+add[o<<1|1]*(r-mid))%mod;}void pushdown(int o,int l,int r){    if (mul[o]!=1)    {        ll p=mul[o];        mul[o]=1;        //(sum[o<<1]*=p)%=mod;        //(sum[o<<1|1]*=p)%=mod;        (add[o<<1]*=p)%=mod;        (add[o<<1|1]*=p)%=mod;        (mul[o<<1]*=p)%=mod;        (mul[o<<1|1]*=p)%=mod;    }    if (add[o]!=0)    {        ll p=add[o];        add[o]=0;    //  (sum[o<<1]+=p*(mid-l+1))%=mod;    //    (sum[o<<1|1]+=p*(r-mid))%=mod;        (add[o<<1]+=p)%=mod;        (add[o<<1|1]+=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==1)        {            (mul[o]*=z)%=mod;            (add[o]*=z)%=mod;        //    (sum[o]*=z)%=mod;        }        if (flag==2)        {            (add[o]+=z)%=mod;        //    (sum[o]+=(r-l+1)*z)%=mod;        }        return;    }    pushdown(o,l,r);    if (x<=mid) update(o<<1,l,mid,x,y,z,flag);    if (y>mid) update(o<<1|1,mid+1,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+1;        int r=(*it).first-1;        int upl=max(L,l);        int upr=min(R,r);        if (upr>=upl)         {            update(1,1,n,upl,upr,inv,1);            update(1,1,n,upl,upr,1,2);        }        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=0;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+1))%mod;//    if (l>=x&&r<=y) return sum[o]%mod;    pushdown(o,l,r);    ll re=0;    if (x<=mid) (re+=query(o<<1,l,mid,x,y))%=mod;    if (y>mid) (re+=query(o<<1|1,mid+1,r,x,y))%=mod;    pushup(o,l,r);    return re; }int main(){    inv=qpow(2,mod-2);    //inv=(mod+1)/2;    n=read();q=read();    for (int i=0;i<=n;i++)     {        st[i].insert(pa(0,0));        st[i].insert(pa(n+1,n+1));    }    build(1,1,n);    while (q--)    {        int opt=read();        if (opt==1)        {            int l=read(),r=read(),z=read();            update(1,1,n,l,r,2,1);            merge(z,l,r);        }        if (opt==2)        {            int l=read(),r=read();            printf("%lld\n",query(1,1,n,l,r));        }    }    return 0;}

[Avito Code Challenge 2018 G] Magic multisets(線段樹)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.