zoukankan      html  css  js  c++  java
  • CF799F Beautiful fountains rows

    CF799F Beautiful fountains rows

    前言

    感觉这3500还挺简单的?可能是因为年代久远的原因?

    F Beautiful fountains rows

    链接

    https://codeforces.ml/contest/799/problem/F

    题意

    n行m列的01矩阵,对于第i行(l_i<=x<=r_i)的是1,其余都是0。数对(a,b)是好的,当且仅当第a列到第b列的矩阵有值为1的点且对于每一行在a到b之间的1的个数为0或奇数。求所有好数对的b-a+1的总和。(1leq n,m leq 200000,1leq l_i leq r_i leq m)

    题解

    显然答案跟每一行的顺序无关。。
    对于每一行,会导致一些数对(a.b)不好
    根据数据结构的套路,这种时候肯定要枚举一个端点。。
    于是从左向右枚举左端点a。
    我们需要维护左端点固定时,右端点有哪些选择。
    首先肯定要维护一下当前还剩哪些1区间需要考虑。
    现在存在的1区间分两种:1.整段都在大于a的位置 2.从a开始就有1
    然后考虑有哪些情况会导致一个数对不好。
    1.全0,这个我们需要维护一下最近从几开始有1.
    2.右端点的选择与第二类区间产生矛盾(偶数个1)
    3.右端点的选择与第一类区间产生矛盾(偶数个1)
    对于2,我们可以维护一下所有这类区间的终点,根据终点的奇偶分类讨论。然后对于3,根据起点,终点,长度的奇偶性各种讨论。。。
    这样肯定是不好写的QAQ。。于是我们考虑再次离线的策略。
    先讨论比较容易讨论的2 。并且将右端点分奇偶两类考虑。
    与a同奇偶的右端点,只要不超过终点与a奇偶不同的区间就行。
    与a不同奇偶的右端点,要不存在终点与a奇偶不同的区间,并且超过终点与a奇偶相同的区间。
    显然这两个合法的部分都是连续的一段奇数或偶数。
    然后把这些连续的段作为3的询问,看这些段里有多少能作为右端点。
    3的区间会导致不好的右端点也需要讨论。
    如果区间长度是偶数,说明区间后面的都不行。
    然后区间内与区间左端L奇偶不同的也一定不行。
    于是问题就变成了区间清零,区间询问的问题,搞个线段树就行了,要分奇偶询问。

    (Code)

    #include<bits/stdc++.h>
    #define LL long long
    #define LD long double
    using namespace std;
    const LL P=998244353;
    const int N=3e5+10;
    const int INF=1e9;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    void pls(LL &x,LL y){
        x+=y;if(x>=P)x-=P;
    }
    int n,m;
    struct Seg{
        int l,r; 
    }a[N];
    bool cmp(Seg x,Seg y){
        return x.l<y.l;
    }
    multiset<int> ed[2];
    multiset<int>::iterator it;
    int cnt;
    struct Query{
        int st,op,l,r;
    }q[N<<1];
    struct Node{
        int l,r;
        LL num[2];
        LL sum[2];
        bool laz[2];
    }d[N<<2];
    #define ls id<<1
    #define rs id<<1|1
    void pushup(int id){
        if(d[id].l==d[id].r) return;
        d[id].num[0]=d[ls].num[0]+d[rs].num[0];
        d[id].num[1]=d[ls].num[1]+d[rs].num[1];
        d[id].sum[0]=d[ls].sum[0]+d[rs].sum[0];
        d[id].sum[1]=d[ls].sum[1]+d[rs].sum[1];
        return;
    }
    void pushdown(int id){
        if(d[id].l==d[id].r) return;
        if(!d[id].laz[0]){
            d[id].laz[0]=1;
            d[ls].num[0]=d[rs].num[0]=0;
            d[ls].sum[0]=d[rs].sum[0]=0;
            d[ls].laz[0]=d[rs].laz[0]=0;
        }
        if(!d[id].laz[1]){
            d[id].laz[1]=1;
            d[ls].num[1]=d[rs].num[1]=0;
            d[ls].sum[1]=d[rs].sum[1]=0;
            d[ls].laz[1]=d[rs].laz[1]=0;
        }
        return;
    }
    void build(int l,int r,int id){
        d[id].l=l;d[id].r=r;
        d[id].num[0]=d[id].num[1]=d[id].sum[0]=d[id].sum[1]=0;
        d[id].laz[0]=d[id].laz[1]=1;
        if(l==r){
            d[id].num[l&1]++;
            d[id].sum[l&1]+=l;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,id<<1);
        build(mid+1,r,id<<1|1);
        pushup(id);
        return;
    }
    
    void update(int l,int r,int id,int op){
        pushdown(id);
        if(d[id].l==l&&d[id].r==r){
            d[id].num[op]=d[id].sum[op]=0;
            d[id].laz[op]=0;
            return;
        }
        if(r<=d[ls].r) update(l,r,ls,op);
        else if(l>d[ls].r) update(l,r,rs,op);
        else{
            update(l,d[ls].r,ls,op);
            update(d[rs].l,r,rs,op);
        }
        pushup(id);
        return;
    }
    
    LL res[2][2];
    
    void ask(int l,int r,int id){
        pushdown(id);
        if(d[id].l==l&&d[id].r==r){
            res[0][0]+=d[id].num[0];
            res[1][0]+=d[id].num[1];
            res[0][1]+=d[id].sum[0];
            res[1][1]+=d[id].sum[1];
            return;
        }
        if(r<=d[ls].r) ask(l,r,ls);
        else if(l>d[ls].r) ask(l,r,rs);
        else{
            ask(l,d[ls].r,ls);
            ask(d[rs].l,r,rs);
        }
        return;
    }
    
    void MAIN(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%d%d",&a[i].l,&a[i].r);
        }
        sort(a+1,a+1+n,cmp);
        cnt=0;
        int cur,L,R;
        for(int i=1,j=1;i<=m;++i){
            while(j<=n&&a[j].l==i){
                ed[a[j].r&1].insert(a[j].r);
                ++j;
            }
            while(!ed[0].empty()){
                it=ed[0].begin();
                if((*it)<i) ed[0].erase(it);
                else break;
            }
            while(!ed[1].empty()){
                it=ed[1].begin();
                if((*it)<i) ed[1].erase(it);
                else break;
            }
            R=m;L=R+1;
            if((!ed[1].empty())||(!ed[0].empty())) L=i;
            if(j<=n) L=min(L,a[j].l);
            cur=i&1;
            if(ed[cur^1].empty()){
                q[++cnt]=(Query){i,cur,L,R};
            }
            else{
                it=ed[cur^1].begin();
                q[++cnt]=(Query){i,cur,L,(*it)};
            }
            if(!ed[cur^1].empty()){
                continue;
            }
            if(ed[cur].empty()){
                q[++cnt]=(Query){i,cur^1,L,R};
            }
            else{
                it=ed[cur].end();
                --it;
                q[++cnt]=(Query){i,cur^1,max(L,(*it)+1),R};
            }
        }
        build(1,m,1);
        LL ans=0;
        for(int i=cnt,j=n;i>=1;--i){
            while(j>=1&&a[j].l>q[i].st){
                cur=a[j].l&1;
                if((a[j].r-a[j].l)&1){
                    if(a[j].r+1<=m) update(a[j].r+1,m,1,cur);
                    update(a[j].l,m,1,cur^1);
                }
                else{
                    update(a[j].l,a[j].r,1,cur^1);
                }
                --j;
            }
            res[0][0]=res[0][1]=res[1][0]=res[1][1]=0;
            if(q[i].l<=q[i].r){
                ask(q[i].l,q[i].r,1);
                ans+=res[q[i].op][1];
                ans-=(LL)(q[i].st-1)*res[q[i].op][0];
            }
        }
        printf("%lld
    ",ans);
        return;
    }
    int main(){
        int ttt=1;
        while(ttt--) MAIN();
        return 0;    
    }
    
  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/14587671.html
Copyright © 2011-2022 走看看