C.冬幕节闹剧 (线段树+离散化)(中国地质大学第十四届ACM华中地区邀请赛19.5.18) 解题报告 Apare

C.冬幕节闹剧(中国地质大学第十四届ACM华中地区邀请赛19.5.18) 解题报告

xzc ccnu 2019.5.20


  这题现场就两个AC的,一个是武大的神仙队,还有一个就是我校的zyf。


题意:

  巫妖王训练军队。他想让某些区间的人戴帽子,某些不戴帽。军队有n个人,他要进行q个操作。(1<=n<=1000,000,000, 1<=1<=50,000) 每个操作为L R op

  • L R表示操作的闭区间
  • op = 1 表示这个区间的人全部不戴帽子
  • op = 2 表示这个区间的人全部要戴帽子
  • op = 3 表示这个区间的人全部状态反转(戴帽子的脱下,没戴帽子的带上)
  • op = 4 表示询问这个区间内戴帽子的人数量

输入格式

n q
L1 R1 op1
L2 R2 op2

Lq Rq opq


Sample

Sample input

3 6 
1 1 1 
1 1 4
1 2 2 
1 2 4
1 3 3 
1 3 4

Sample output

0
1
2

还有一个zyf给我的样例
input

10000 5
1 5000 2
1 2500 1
1 5000 4
1 10000 3
1 10000 4

output

2500
2500

思路:

  • 显然是线段树
  • n很大,要离散化

我的做法

  1. 如果不考虑离散化,我们先考虑线段树维护的是什么
    线段树维护区间的状态flag。我们可以转化为染色问题。
  • flag为0代表这个区间[left,right]所有的士兵都没戴帽子,
  • flag为1代表这个区间所有士兵都带了帽子
  • flag为-1代表不统一
  1. 然后我们考虑离散化的问题:
  • 因为线段树维护的是一段区间,而我们离散化后的都是离散的点。所以我们需要进行一些处理
    先看一组样例吧

设所有操作设计的区间有3个:[3,8],[15,16],[16,30]
我们将所有的Ri+1也一同离散化
先看一个表格

序号 1 2 3 4 5 6 7 8
端点(数组a ) 3 8 9 15 16 17 30 31
线段表示的范围 [3,7] [8,8] [9,14] [15,15] [16,16] [17,29] [30,30]
线段树的叶子节点 [1,1] [2,2] [3,3] [4,4] [5,5] [6,6] [7,7]

  从这个表,我们可以很清楚的看到,线段树维护的其实是一个坐闭右开的区间。所以我们需要把Ri+1一起离散化,然后就可以多出一个[Ri,Ri]的闭区间。
  每个区间[left,right]维护的范围正好是[a[left],a[right+1]]
  这样的话,我们就可以像不离散化一样维护线段树了

关于线段树的部分

  • 对于update操作(1和2),如果要更新的区间[uL,uR]和线段树当前节点表示的区间[left,right]重合,j就直接把区间标记flag[pos]改掉;否则pushdown()递归向下更新,然后pushup()
  • 对于reverse操作(3),如果重合且区间状态一样,就直接flag[pos]^=1,return;否则向下递归
  • 对于查询,同更新,不用pushup
  • 有些暴力,但是没有被卡掉(145ms)
  • zyf写的是lazy[]和sum[],维护的是区间和,这样不会被卡
  • 具体见代码

我的代码:

/************************************************************** Problem: 2181 User: apare Language: C++ Result: 正确 Time:172 ms Memory:6884 kb ****************************************************************/
#include <bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
#define MP make_pair
#define pb push_back
using namespace std;
const int maxn = 2e5+30;
const int maxq = 5e4+20;
//向zyf看齐 
int flag[maxn<<2]; //0都没有,1都有,-1杂色 
int cnt;
int qL[maxq],qR[maxq];
int a[maxn];
struct Node{
    int L,R,op;
    void input()
    {
        scanf("%d%d%d",&L,&R,&op);
        a[++cnt] = L;
        a[++cnt] = R;
        a[++cnt] = R+1;
    }
}node[maxq]; 
void build(int left,int right,int pos=1);
void push_down(int pos);
void push_up(int pos);
void update(int left,int right,int uL,int uR,int op,int pos);
void Reverse(int left,int right,int uL,int uR,int pos);
int query(int left,int right,int qL,int qR,int pos);
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        cnt = 0;
        For(i,1,q)
        {
            node[i].input();
        }
        sort(a+1,a+1+cnt);
        cnt = unique(a+1,a+cnt+1)-a-1;
        cnt--;
        For(i,1,q)
        {
            qL[i] = lower_bound(a+1,a+cnt+1,node[i].L)-a;
            qR[i] = lower_bound(a+1,a+cnt+1,node[i].R)-a;
        }
        build(1,cnt);
        For(i,1,q)
        {
            switch (node[i].op)
            {
                case 1: update(1,cnt,qL[i],qR[i],0,1);break;
                case 2: update(1,cnt,qL[i],qR[i],1,1);break;
                case 3: Reverse(1,cnt,qL[i],qR[i],1);break;
                case 4: printf("%d\n",query(1,cnt,qL[i],qR[i],1));break;
            }
        }
    }  
    return 0;
}
void build(int left,int right,int pos)
{
    if(left==right)
    {
        flag[pos] = 0;
        return;
    }
    int mid = (left+right)>>1;
    build(left,mid,pos<<1);
    build(mid+1,right,pos<<1|1);
} 
void push_down(int pos)
{
    if(flag[pos]!=-1) 
        flag[pos<<1] = flag[pos<<1|1] = flag[pos]; 
}
void push_up(int pos)
{
    flag[pos] = (flag[pos<<1]==flag[pos<<1|1])?flag[pos<<1]:-1;
}
void update(int left,int right,int uL,int uR,int op,int pos)
{
    if(left==uL&&right==uR)
    {
        flag[pos] = op;
        return;     
    } 
    push_down(pos);
    int mid = (left+right)>>1;
    if(uL>mid) 
        update(mid+1,right,uL,uR,op,pos<<1|1);
    else if(uR<=mid) 
        update(left,   mid,uL,uR,op,pos<<1);
    else
        update( left,  mid,   uL,mid,op,pos<<1),
        update(mid+1,right,mid+1, uR,op,pos<<1|1);
    push_up(pos);
     
}
void Reverse(int left,int right,int uL,int uR,int pos)
{
    if(left==uL&&right==uR&&flag[pos]!=-1)
    {
        flag[pos]^=1;
        return;
    }
    push_down(pos);
    int mid = (left+right)>>1;
    if(uL>mid) 
        Reverse(mid+1,right,uL,uR,pos<<1|1);
    else if(uR<=mid) 
        Reverse(left,   mid,uL,uR,pos<<1);
    else
        Reverse( left,  mid,   uL,mid,pos<<1),
        Reverse(mid+1,right,mid+1, uR,pos<<1|1);
    push_up(pos);
}
int query(int left,int right,int qL,int qR,int pos)
{
    if(left==qL&&qR==right&&flag[pos]!=-1)
    { 
        return flag[pos]?a[right+1]-a[left]:0;
    }
    push_down(pos);
    int mid = (left+right)>>1;
    if(qL>mid) 
        return query(mid+1,right,qL,qR,pos<<1|1);
    else if(qR<=mid) 
        return query(left,   mid,qL,qR,pos<<1);
    else
        return query( left,  mid,   qL,mid,pos<<1)
        +      query(mid+1,right,mid+1, qR,pos<<1|1);
}


全部评论

相关推荐

点赞 评论 收藏
分享
10-25 02:13
门头沟学院 C++
_凡_:8.27笔试10.22评估
投递小米集团等公司10个岗位
点赞 评论 收藏
分享
11-08 10:39
门头沟学院 C++
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务