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
思路:
我的做法
- 如果不考虑离散化,我们先考虑线段树维护的是什么
线段树维护区间的状态flag。我们可以转化为染色问题。
- flag为0代表这个区间[left,right]所有的士兵都没戴帽子,
- flag为1代表这个区间所有士兵都带了帽子
- flag为-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);
}