「题解」:联

问题 A: 联

时间限制: 2 Sec  内存限制: 256 MB

题面



题面谢绝公开。

题解



解法1:离散化+线段树。

1e18的数据范围直接离散化掉所有的l和r,加一个映射数组表示间距即可。

线段树维护区间和,扫0的时候判定子树和等不等于子树大小。

维护两个标记:lazy(将一个区间赋值成什么)、xr(是否异或整个区间)跑就完了。

(我会说我沉迷解法二而解法一是水的么 感谢Larry提供的优质讲解及代码)

#include<bits/stdc++.h>
#define int long long
#define rint register int
using namespace std;
int m,a[200005<<1],tot=0,cnt;
struct Tree{int l,r,sum,laz,flag;}t[200005<<3];
struct node{int l,r,val;}qu[200005];
inline void pushup(int k){t[k].sum=t[k<<1].sum+t[k<<1|1].sum;}
inline void build(int k,int l,int r)
{
    t[k].l=l,t[k].r=r,
    t[k].laz=-1,t[k].sum=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(k<<1,l,mid),build(k<<1|1,mid+1,r);
}
inline void down(int k)
{
    int linl=t[k].l,linr=t[k].r,mid=(linl+linr)>>1;
    if(t[k].laz!=-1)
    {
        t[k<<1].laz=t[k<<1|1].laz=t[k].laz;
        t[k<<1].sum=t[k].laz*(mid-linl+1),t[k<<1|1].sum=t[k].laz*(linr-mid);
        t[k<<1].flag=t[k<<1|1].flag=0;t[k].laz=-1;
    }
    if(t[k].flag)
    {
        t[k<<1].flag^=1;t[k<<1|1].flag^=1;t[k].flag=0;
        t[k<<1].sum=(mid-linl+1)-t[k<<1].sum;t[k<<1|1].sum=(linr-mid)-t[k<<1|1].sum;
    }
    return ;
}
inline void change(int k,int l,int r,int val)
{
    int linl=t[k].l,linr=t[k].r;
    if(l<=linl&&linr<=r)
    {
        t[k].sum=val*(linr-linl+1);
        t[k].laz=val;t[k].flag=0;
        return ;
    }
    down(k);
    int mid=(linl+linr)>>1;
    if(l<=mid) change(k<<1,l,r,val);
    if(r>mid) change(k<<1|1,l,r,val);
    pushup(k);
}
inline void Xor(int k,int l,int r)
{
    int linl=t[k].l,linr=t[k].r;
    if(l<=linl&&linr<=r)
    {
        t[k].flag^=1;
        t[k].sum=(linr-linl+1)-t[k].sum;
        return ;
    }
    down(k);
    int mid=(linl+linr)>>1;
    if(l<=mid) Xor(k<<1,l,r);
    if(r>mid) Xor(k<<1|1,l,r);
    pushup(k);
}
inline int query(int k)
{
    int linl=t[k].l,linr=t[k].r;
    if(linl==linr) return linl;
    down(k);
    int mid=(linl+linr)>>1;
    if(t[k<<1].sum<(mid-linl+1)) return query(k<<1);
    else return query(k<<1|1);
}
signed main()
{
    scanf("%lld",&m);
    a[++tot]=1;
    for(rint i=1;i<=m;++i)
    {
        scanf("%lld %lld %lld",&qu[i].val,&qu[i].l,&qu[i].r);
        a[++tot]=qu[i].l,a[++tot]=qu[i].r+1;
    }
    sort(a+1,a+tot+1);
    cnt=unique(a+1,a+tot+1)-a-1;
    build(1,1,cnt);
    for(rint i=1;i<=m;++i)
    {
        qu[i].l=lower_bound(a+1,a+cnt+1,qu[i].l)-a;
        qu[i].r=lower_bound(a+1,a+cnt+1,qu[i].r+1)-a-1;
        if(qu[i].val==1) change(1,qu[i].l,qu[i].r,1);
        else if(qu[i].val==2) change(1,qu[i].l,qu[i].r,0);
        else Xor(1,qu[i].l,qu[i].r);
        printf("%lld\n",a[query(1)]);
    }
    return 0;
}

线段树解法

解法2:这怕是个ODT裸题(emm可能有人不知道ODT这个高端大气的名字,那珂朵莉树应该无人不晓了吧2333)

代码里面有注释。(一会儿去补一篇珂朵莉树学习笔记)

(还是要%%%羊驼神赛时打珂朵莉树。面对满屏幕的编(炸)译(库)信息我真的要崩溃了的说。)

#include<bits/stdc++.h>
#define read(A) A=init()
#define rint register int
#define ll long long
#define inf 1000000000000000000
using namespace std;
inline int init()
{
    int a=0,b=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)b=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){a=(a<<3)+(a<<1)+ch-‘0‘;ch=getchar();}
    return a*b;
}
int m;
struct node{
    ll l,r;mutable int val;
    friend bool operator < (const node &A,const node &B){
        return A.l<B.l;
    }
};
set <node> s;
inline set<node>::iterator split(ll k)
{
    set<node>::iterator it=s.lower_bound((node){k,0,-1});
    if(it->l==k)return it;//若搜索的l是刚好一个区间的l,则会得到这个区间的位置
    it--;//否则会得到靠后的一个区间,此时--得到之前的区间
    ll linl=it->l,linr=it->r,linv=it->val;//取出当前区间的l、r、val
    s.erase(it);//暴力删除当前区间
    s.insert((node){linl,k-1,linv});//将区间切割,将l-1与前区间的l形成新区间插回
    return s.insert((node){k,linr,linv}).first;//返回值为pair,第一维为地址
}
inline void change(ll l,ll r,int val)
{
    set<node>::iterator itr=split(r+1),itl=split(l);//先通过切割取出集合左右端点
    s.erase(itl,itr);//直接删除一个集合
    s.insert((node){l,r,val});//把区间重新插回去
}
inline void Xor(ll l,ll r)
{
    set<node>::iterator itr=split(r+1),itl=split(l);//切出最左边的区间和最右边的区间
    for(set<node>::iterator i=itl;i!=itr;++i)i->val^=1;//对于每一个区间权值直接异或
}
inline ll get_ans()
{
    for(set<node>::iterator i=s.begin();i!=s.end();++i)
        if(i->val==0)return i->l;
    return (*--s.end()).r+1;
}
int main()
{
    read(m);
    s.insert((node){1,inf,0});
    for(rint i=1,ty;i<=m;++i)
    {
        ll lb,rb;read(ty);
        scanf("%lld %lld",&lb,&rb);
        if(ty==1)change(lb,rb,1);
        if(ty==2)change(lb,rb,0);
        if(ty==3)Xor(lb,rb);
        printf("%lld\n",get_ans());
    }
    return 0;
}

珂朵莉树解法

原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11610807.html

时间: 2024-10-11 12:10:53

「题解」:联的相关文章

「题解」kuangbin 最小生成树

POJ-1251 Jungle Roads (水题,%c) POJ-1287 Networking (水) POJ-2031 Building a Space Station (%f浮点数尴尬精度,两球间距离) POJ-2421 Constructing Roads (一些边已建好,简单处理一下) ZOJ-1586 QS Network (处理一下边权) HDU-1233 还是畅通工程 (水) HDU-1875 畅通工程再续 (浮点数,条件连边) HDU-1301 Jungle Roads (重

「题解」「美团 CodeM 资格赛」跳格子

目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞定,最后无奈 \(90pts\) . 然而 \(T2\) 想到很多很奇怪的做法,结果正解在 \(28min\) 之内做出... 结果 \(T3\) 是本人最不擅长的伪期望,直接跳过,啥都没得. 来水一发 \(T1\) 的题解... 题目描述 点这里 考场思路 其实并没有什么十分特别的思路,就是一通乱

「题解」:[loj2763][JOI2013]现代豪宅

问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东西方向$M$列,南北方向$N$行的正方形房间组成. 从西面开始第$x$列,从南面开始第y行的房间用$(x,y)$表示. 相邻的两个房间之间都有一扇门.对于每扇门,门关上表示不可通行,门打开表示可以通行. 当门打开时,从门一边的房间走到另一边的房间需要$1$分钟. 另外,一些房间中有一个开关,如果连续

「题解」:世界线

问题 A: 世界线 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 我刚学完bitset就考了???然而我赛时并没有想到是bitset…… 话说我bitset还是没有颓完啊赶紧去补一波时空复杂度…… bitset优化暴力(据某诺神说这是bitset果题??) 注意dfs的时侯如果目标节点已经搜过了直接用当前节点的bitset或上目标节点的bitset值即可. 还有$6e4×6e4$会炸空间.开一个$6e4×3e2$的然后一半一半跑即可. 至于怎么跑一半,直接判断和

「题解」:X国的军队

问题 A: X国的军队 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 简单贪心. 按照存活的士兵数量(即参加战斗的士兵数量减去阵亡的士兵数量)排序. 若存活士兵数量相同则按照参与战斗的士兵数量排序. 顺序扫一遍统计答案. #include<bits/stdc++.h> #define int long long #define rint register int #define read(A) A=init() using namespace std; inl

「题解」:Simple

问题 A: Simple 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 不算数学的数学题?? 直接枚举会重.$60%$两种算法:1.无脑$vis$数组记录.2.$exgcd$解方程判定是否有解. $100%$:首先考虑特殊情况:$n$.$m$互质. 我们设$n*x+m*y=z$,考虑枚举$y$和$x$,不难发现,当$y>=x$的时候均能找到一个$y'$使得$n|(y-y')$. 于是会出现重复.因此只需枚举$y([0,n-1])$,计算贡献即可. 对于一般情况,

「题解」:e

问题 B: e 时间限制: 2 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 话说一天考两个主席树这回事…… 正解可以叫树上主席树??(脸哥说也叫主席树上树???) 对于树上的每一条链建主席树,支持链上查询前驱和后继. 对于所有的$p[i]$,他说怎么得到就按他说的做就好,然后求所有$p[i]$的$LCA$. 对于每个$p[i]$到$LCA$的链上查一次$r$的前驱和后继更新答案即可. 注意:参数不要传反.别一个特判把自己判掉.pre和nxt的代码不要粘贴,粘贴了不要忘记改掉内

「题解」:毛一琛/$cow$ $subsets$

问题 A: 毛一琛/$cow$ $subsets$ 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 题名貌似是个大神??看起来像是签到题然后就死了. 首先$O(3^n)$算法显然.也显然过不去$20$的测试点. 正解是赫赫有名的$meet$ $in$ $the$ $middle$算法.数据在40以内的都能用$meet$ $in$ $the$ $middle$?? 对于两半路径,可以拼起来并且构成合法答案的条件是两人获得的分数相同. 所以一个比较聪明的办法是,不去记

「题解」:毛三琛

问题 C: 毛三琛subset 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 一眼题解随机化,吓够呛.一句话题解:二分答案加剪枝. 外层枚举$x$,然后二分答案暴力$check$.如果当前答案对于x的check失败就continue, 因为在当前的x中不可能找到比当前答案更优秀的解.加clock卡常可以A. 貌似不需要看脸.毕竟我这个非洲人都一遍A了.复杂度$O(np+nlognlogp)$. 代码:(ps.$¥$神指出了我代码的缺陷:其实在外面直接赋值可以少一