CSUOJ nineteen thirteen One big silly dragon gives gifts out 线段树 二分 转化
2017-06-07 16:53
603 查看
标题含有敏感词,莫名被锁了2次。OTZ,用英文总该没事
Description
这天一条大笨龙(菜比出题人dota2游戏名称)的好朋友高素质玩家(某素质玩家dota2游戏名称)天天被朋友黑,一条大笨龙觉得太可怜了,一条大笨龙准备送点礼物给他作为安慰。一条大笨龙现在有一个长度为n的整数序列。
然而他的这个好朋友非常喜欢鸽子,他有想对这个序列进行某种变形操作(第一类操作),给出一些区间[l,r],要求把区间[l, r]的数字变成飞翔的鸽子的翅膀形状(如下图)(注:可能会没有图,源地址为 点击打开链接 ,而且图上有一个错误,就是2和3应该交换位置),进行重新排列。
即是说将数字从大到小依次放在鸽子的左右翅膀上面,然后形成一个新的序列。
不仅如此,由于这个朋友还是一个善变的人,在进行上述操作的过程中也可能进行另外一种操作(第二类操作),给出一个数p,将序列变回p个第一类操作之前的状态。两种操作总共进行m次后,他只挑走这个序列的第k个数给拿走当作自己的礼物。
一条大笨龙想知道最后被拿走的这个数的值是多少。
Input
第1行:n
,m,k (1<=n,m,k<=5e4)
第2行:n个数,每个数a[i],表示初始序列
1<=a[i]<=2e5
第3~m+2行:
如果是第一类操作,有三个数:1 L R
,表示对区间[L,R]进行上述操作
否则是第二类操作,有两个数:2 p
,撤销最近的p个第一类操作,如果p比第一类操作数的数量还大,那么将序列恢复成最原始的状态。
上述操作中
1<=L<=R<=n
1<=p<=m
Output
一个数,被拿走的值
Sample Input
8 10 4
15 4 12 3 14 145 2
2 4
1 4 5
1 6 6
2 1
1 5 8
1 4 5
1 1 3
1 1 7
1 3 8
2 1
Sample Output
2
不知道做。
正确的做法是线段树,然后考虑怎么转化这个操作。
首先把所有的操作用一个vector存起来,存的过程中顺便把2号操作给实现掉,剩下的就是真正需要做的操作
然后二分最后的答案ans,将数组里大于ans的数设置为1,小于ans的数设置为0,线段树里维护的就是这样一个01数组,然后对于这个01数组就可以很好的进行1号操作了。
比如,考虑在区间L~R上进行1号操作,首先求出L~R的区间和sum,然后把区间左边的sum/2位设置为1(假若sum是奇数,则应该是sum/2+1),右边的sum/2位设置为1,中间的位设置为0。这样,这个操作就变成了3个区间赋值的操作。
最后query第k的数,假若第k位是0,则代表真正的答案Tans<=ans,否则Tans>ans
可以仔细理解一下,第一次做线段树+二分的题目
Description
这天一条大笨龙(菜比出题人dota2游戏名称)的好朋友高素质玩家(某素质玩家dota2游戏名称)天天被朋友黑,一条大笨龙觉得太可怜了,一条大笨龙准备送点礼物给他作为安慰。一条大笨龙现在有一个长度为n的整数序列。
然而他的这个好朋友非常喜欢鸽子,他有想对这个序列进行某种变形操作(第一类操作),给出一些区间[l,r],要求把区间[l, r]的数字变成飞翔的鸽子的翅膀形状(如下图)(注:可能会没有图,源地址为 点击打开链接 ,而且图上有一个错误,就是2和3应该交换位置),进行重新排列。
即是说将数字从大到小依次放在鸽子的左右翅膀上面,然后形成一个新的序列。
不仅如此,由于这个朋友还是一个善变的人,在进行上述操作的过程中也可能进行另外一种操作(第二类操作),给出一个数p,将序列变回p个第一类操作之前的状态。两种操作总共进行m次后,他只挑走这个序列的第k个数给拿走当作自己的礼物。
一条大笨龙想知道最后被拿走的这个数的值是多少。
Input
第1行:n
,m,k (1<=n,m,k<=5e4)
第2行:n个数,每个数a[i],表示初始序列
1<=a[i]<=2e5
第3~m+2行:
如果是第一类操作,有三个数:1 L R
,表示对区间[L,R]进行上述操作
否则是第二类操作,有两个数:2 p
,撤销最近的p个第一类操作,如果p比第一类操作数的数量还大,那么将序列恢复成最原始的状态。
上述操作中
1<=L<=R<=n
1<=p<=m
Output
一个数,被拿走的值
Sample Input
8 10 4
15 4 12 3 14 145 2
2 4
1 4 5
1 6 6
2 1
1 5 8
1 4 5
1 1 3
1 1 7
1 3 8
2 1
Sample Output
2
不知道做。
正确的做法是线段树,然后考虑怎么转化这个操作。
首先把所有的操作用一个vector存起来,存的过程中顺便把2号操作给实现掉,剩下的就是真正需要做的操作
然后二分最后的答案ans,将数组里大于ans的数设置为1,小于ans的数设置为0,线段树里维护的就是这样一个01数组,然后对于这个01数组就可以很好的进行1号操作了。
比如,考虑在区间L~R上进行1号操作,首先求出L~R的区间和sum,然后把区间左边的sum/2位设置为1(假若sum是奇数,则应该是sum/2+1),右边的sum/2位设置为1,中间的位设置为0。这样,这个操作就变成了3个区间赋值的操作。
最后query第k的数,假若第k位是0,则代表真正的答案Tans<=ans,否则Tans>ans
可以仔细理解一下,第一次做线段树+二分的题目
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #define mid ((le+ri)>>1) #define lson (node<<1) #define rson (node<<1|1) #define lc lson,le,mid #define rc rson,mid+1,ri #define sc node,le,ri using namespace std; typedef pair<int,int> pa; const int maxm=5E4+10; int arr[maxm],k,st[maxm*5],x,y,val,lazy[maxm*5],n,m,query(int node=1,int le=1,int ri=n); void init(int node=1,int le=1,int ri=n),update(int node=1,int le=1,int ri=n),pushdown(int node,int le,int ri),pushup(int node); vector<pa> v; bool judge(int mi); int main(){ ios_base::sync_with_stdio(0); while(cin>>n>>m>>k){ for(int i=1;i<=n;++i) cin>>arr[i]; for(int ord;m;--m){ cin>>ord; if(ord-1){ cin>>val; while(!v.empty()&&val--)v.pop_back(); }else{ cin>>x>>y; v.push_back(make_pair(x,y)); } } int le=1,ri=2E5; while(ri>le+1)(judge(mid)?le:ri)=mid; cout<<(judge(le)?ri:le)<<endl; v.clear(); } return 0; } void init(int node,int le,int ri){ lazy[node]=-1; if(le==ri){ st[node]=arr[le]>val; }else{ init(lc); init(rc); pushup(node); } } void pushup(int node){ st[node]=st[lson]+st[rson]; } void pushdown(int node,int le,int ri){ if(lazy[node]!=-1){ lazy[lson]=lazy[rson]=lazy[node]; st[lson]=(mid-le+1)*lazy[node]; st[rson]=(ri-mid)*lazy[node]; lazy[node]=-1; } } int query(int node,int le,int ri){ if(ri<x||le>y)return 0; if(x<=le&&ri<=y) return st[node]; else{ pushdown(sc); return query(lc)+query(rc); } } void update(int node,int le,int ri){ if(ri<x||le>y)return; if(x<=le&&ri<=y){ lazy[node]=val; st[node]=(ri-le+1)*lazy[node]; }else{ pushdown(sc); update(lc); update(rc); pushup(node); } } bool judge(int mi){ val=mi; init(); for(int i=0,tmp;i<v.size();++i){ x=v[i].first,y=v[i].second; tmp=query(); val=1; y=x+(tmp>>1)+(tmp&1)-1; update(); y=v[i].second,x=y-(tmp>>1)+1; update(); x=v[i].first+(tmp>>1)+(tmp&1),y-=(tmp>>1),val=0; update(); } x=y=k; return query(); }
相关文章推荐
- csuoj1303(将循环小数转化为分数)
- Qz’s Maximum All One Square+csuoj+dp
- swust oj one+two=3(0287)——单词和数字的转化
- CSU1553 Good subsequence —— 二分 + RMQ/线段树
- CSU 1913: 送礼物 (二分答案 + 线段树)
- CSUOJ 1542 线段树解决括号反向问题
- CSUOJ 1411 Longest Consecutive Ones
- [bzoj4552][Tjoi2016&Heoi2016]排序-二分+线段树
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- HDU5930 gcd (线段树 + 二分)
- CSUOJ 1005 Binary Search Tree analog
- bzoj 4556: [Tjoi2016&Heoi2016]字符串 (主席树+二分+后缀数组+ST表||后缀自动机+线段树合并+LCA)
- [CFNews] ComputerWorld:IBM melds crime-fighting, big data analytics in one security package
- CSU OJ 1120 病毒(湖南省第八届大学生计算机程序设计竞赛)
- HDU 5954 Do not pour out(二分+积分)
- 【Cf #291 B】R2D2 and Droid Army(二分,线段树)
- HDU 4614 Vases and Flowers (线段树 + 二分)
- CSU 1335 高桥和低桥(二分)
- CSUOJ 1005 Binary Search Tree analog(二叉搜索树模拟)
- HDU 6070 Dirt Ratio(二分+线段树 17多校第四场)