hdu 5338 ZZX and Permutations (贪心+线段树+二分)
ZZX and Permutations
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 24 Accepted Submission(s): 2
ZZX knows that a permutation can be decomposed into disjoint cycles(see https://en.wikipedia.org/wiki/Permutation#Cycle_notation). For example:
145632=(1)(35)(462)=(462)(1)(35)=(35)(1)(462)=(246)(1)(53)=(624)(1)(53)……
Note that there are many ways to rewrite it, but they are all equivalent.
A cycle with only one element is also written in the decomposition, like (1) in the example above.
Now, we remove all the parentheses in the decomposition. So the decomposition of 145632 can be 135462,462135,351462,246153,624153……
Now you are given the decomposition of a permutation after removing all the parentheses (itself is also a permutation). You should recover the original permutation. There are many ways to recover, so you should find the one with largest lexicographic order.
t,
the number of test cases.
Then t
testcases follow. In each testcase:
First line contains an integer n,
the size of the permutation.
Second line contains n
space-separated integers, the decomposition after removing parentheses.
n≤105.
There are 10 testcases satisfying n≤105,
200 testcases satisfying n≤1000.
space-separated numbers in a line for each testcase.
Don't output space after the last number of a line.
2
6
1 4 5 6 3 2
2
1 2
4 6 2 5 1 3
2 1
题意是给你一个n个数以内的组合,每一个数取1~n,告诉你一个循环变化标记又去掉括号后的数组,要你将这个数组还原成字典序最大的组合排列。
首先明白题意,比如1 4 5 6 3 2,用ans[i]表示答案位置i上的值。a[i]表示输入的数组。id[i]表示数值i在a[]中的位置。
求解时,ans[1]能取1或者4, 此时当然贪心取4就好了,对4这个值我们标记一下已经用过了,对ans[1]就得到答案了,位置1标记一下已经解出了答案了。但我们不确定位置4。由于4可能取1也可能取5。我们后面再讨论。
ans[2]能取1 5 6 3中的随意一个值,由于4这个值已经用过了,所以不能再用,贪心取最大值6。所以这个动态算最大值的时候要用到线段树维护最大值,由于最大值6在a[]中的i=4而2在a[]中的i=6,所以必定构成2<-6<-3<-2这样的环。对于情况可以直接确定ans[2],ans[6],ans[3]的值,对于位置2,6,3标记已经解出答案了,对值6。 3, 2标记已经用过了,从线段树里删除(set l=4 r=6 value=0)。对区间[4,6]标记已经确定了。不能从区间后面跨过去取区间前面的数,所以用个二分的结构把这个区间[l=4,r=6]丢进去,我用的map反正保证插入时是logn。树上二分的话也是logn。每次要用线段树查找最大值时,就不能跨过这些已经确定位置的区间,所以每次二分一下可以查找最大值的区间;
ans[3]解过答案,跳过就好。
ans[4]能够取1或者5,因为5更大且没被用过所以贪心取5。把5标记已经用过这个值了,从线段树里删掉5,把4这个位置标记一下。已经确定了;
ans[5]能够取线段树在区间[1,3]中找到的最大值。由于4和5都删掉了。也就是1还能取,那么就连上。对于这样的把区间[1,3]就都定下来了。把区间[1,3]丢到二分的结构里;
ans[6]解过答案,跳过就好;
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map> using namespace std; const int maxn = 100010;
typedef long long LL; int a[maxn], vidx[maxn];
int vis[maxn], flg[maxn]; namespace SegmentTree{
int maxv[maxn<<2]; int setv[maxn<<2];
#define Lson o<<1
#define Rson o<<1|1 void pushup(int o){
maxv[o] = max(maxv[Lson], maxv[Rson]);
} void build(int o, int l, int r){
int m = (l+r)>>1;
if(l == r){
maxv[o] = a[l];
setv[o] = -1;
}
else {
build(Lson, l, m);
build(Rson, m+1, r);
setv[o] = -1;
pushup(o);
}
} void pushdown(int o){
if (setv[o] >= 0){
setv[Lson] = setv[Rson] = setv[o];
maxv[Lson] = maxv[Rson] = setv[o];
setv[o] = -1;
}
} int v, ul, ur;
void update(int o, int l, int r){
if(l > r) return ;
if (ul <= l && r <= ur){
setv[o] = v;
maxv[o] = v;
}
else{
pushdown(o);
int m = (l+r)>>1;
if (ul <= m) update(Lson, l, m);
if (ur > m) update(Rson, m+1, r);
pushup(o);
}
} int _max, ql, qr;
void query(int o, int l, int r){
if(l>r) return ;
if (setv[o] >= 0){
_max = max(_max, setv[o]);
}
else if (ql <= l && r <= qr){
_max = max(_max, maxv[o]);
}
else {
int m = (l+r)>>1;
pushdown(o);
if(ql <= m) query(Lson, l, m);
if(qr > m) query(Rson, m+1, r);
}
} } namespace BS{ typedef pair<int,int> seg;
#define l first
#define r second
#define MP make_pair
int n; map<int,int> mp; void init(){
mp.clear();
} void add(int l, int r){
seg line = MP(l, r);
mp.insert(line);
} int search(int v){ map<int,int>::iterator it = mp.upper_bound(v); if (it == mp.begin()){
return 0;
}
else{
--it;
return it->r;
}
}
} int ans[maxn];
void link(int l, int r){
for(int i=l; i<r; i++){
ans[a[i]] = a[i+1];
}
ans[a[r]] = a[l];
} int main(){
// freopen("data.in", "r", stdin);
int T, n;
scanf("%d",&T);
while(T--){
scanf("%d", &n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
vidx[a[i]] = i;
} memset(vis, 0, sizeof vis);
memset(flg, 0, sizeof flg);
SegmentTree::build(1,1,n);
BS::init();
for(int _i=1;_i<=n;_i++){
int i = vidx[_i];
if (vis[i]) continue; int id = i, mx=0;
if(!flg[_i]) mx = _i; SegmentTree::ql = BS::search(i) + 1;
SegmentTree::qr = id-1;
SegmentTree::_max = 0;
SegmentTree::query(1,1,n); mx = max(mx, SegmentTree::_max);
if (!vis[i+1] && i < n){
mx = max(mx, a[i+1]); //把a[i+1]放到i位置
if (mx == a[i+1]){
ans[_i] = a[i+1];
flg[a[i+1]] = 1; SegmentTree::ul = i+1;
SegmentTree::ur = i+1;
SegmentTree::v = 0;
SegmentTree::update(1,1,n); continue;
}
} //把vidx[mx]放到i
int l = min(vidx[mx], i),r = max(vidx[mx], i);
link(l, r);
for(int j = l; j <= r; j++){
vis[j] = 1;
flg[a[j]] = 1;
}
BS::add(l, r);
SegmentTree::ul = l;
SegmentTree::ur = r;
SegmentTree::v = 0;
SegmentTree::update(1,1,n);
}
for(int i=1; i <= n; i++){
printf("%d%c", ans[i], i<n?' ':'\n');
}
} return 0;
}
hdu 5338 ZZX and Permutations (贪心+线段树+二分)的更多相关文章
- HDU 5338 ZZX AND PERMUTATIONS 线段树
pid=5338" target="_blank" style="text-decoration:none; color:rgb(45,125,94); bac ...
- 2015 Multi-University Training Contest 4 hdu 5338 ZZX and Permutations
ZZX and Permutations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/O ...
- HDU 4614 Vases and Flowers(线段树+二分)
Vases and Flowers Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others ...
- [JZOJ6400]:Game(贪心+线段树+二分)
题目描述 小$A$和小$B$在玩一个游戏,他们两个人每人有$n$张牌,每张牌有一个点数,并且在接下来的$n$个回合中每回合他们两人会分别打出手中的一张牌,点数严格更高的一方得一分,然而现在小$A$通过 ...
- 线段树+树状数组+贪心 HDOJ 5338 ZZX and Permutations
题目传送门 /* 题意:不懂... 线段树+树状数组+贪心:贪心从第一位开始枚举,一个数可以是循环节的末尾或者在循环节中,循环节(循环节内部是后面的换到前面,最前面的换到最后面).线段树维护最大值,树 ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
- hdu 5274 Dylans loves tree(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- BZOJ4391 High Card Low Card [Usaco2015 dec](贪心+线段树/set库
正解:贪心+线段树/set库 解题报告: 算辣直接甩链接qwq 恩这题就贪心?从前往后从后往前各推一次然后找一遍哪个地方最大就欧克了,正确性很容易证明 (这里有个,很妙的想法,就是,从后往前推从前往后 ...
- HDU 3074.Multiply game-区间乘法-线段树(单点更新、区间查询),上推标记取模
Multiply game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
随机推荐
- POJ-1061 青蛙的约会 (扩展欧几里得)
[题目描述] 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有 ...
- Android自动化测试Uiautomator--UiScrollable接口简介
UiScrollable主要包括以下几个方面的方法: 1.快速滚动 2.获取列表子元素 3.获取与设置最大滚动次数常量值 4.滑动区域校准常量设置与获取 5.先前与向后滚动 6.滚动到某个对象 7.设 ...
- java foreach的实现原理
http://blog.csdn.net/moqihao/article/details/51078464 本质是通过集合的iterator方式实现,所以再使用foreach集合,要强制判断集合的是否 ...
- PYDay3-初识python
Python 种类 c.j.iron.ruby等,主要有三类:cpython.xxxpython.pypy 种类繁多我们精通一种即可 编译流程: py代码->字节码->机器码->计算 ...
- Appium启动app
首先要获取包名,然后获取launcherActivity.获取这两个关键东西的方法很多,这里就不一一多说,小伙伴们可以各显神通.小编这里主要给大家推荐一个sdk自带的实用工具aapt. aapt即An ...
- SQL server将查询到的多行结果,拼接成字符串(列转行)
select stuff(( ,,'') as UserNamestr 注释:查询出tabname表中的UserName列的所有内容,并将内容拼接成UserNamestr
- TOJ3039: 材质贴图
3039: 材质贴图 Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByteTotal Submit: 46 ...
- HDU-4825 Xor Sum,字典树好题!
Xor Sum 一遍A了之后大呼一声好(keng)题!debug了两小时~~~~百度之星资格赛,可以. 题意:给你一个n个元素的数组,m次查询,每次输入一个数k要求从数组中找到一个数与k异或值最大,输 ...
- 九度oj 题目1140:八皇后
题目描述: 会下国际象棋的人都很清楚:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题. 对于某个满足要求的 ...
- linux移动硬盘unmount报错处理
备份数据用的移动硬盘unmount时报: 通过fuser命令来kill掉设备进程,再unmount移动设备 先看fuser命令帮助信息: [root@athenadb2 ~]# fuser -help ...