Gym 102001H —— Lexical Sign Sequence
原题链接:http://codeforces.com/gym/102001/problem/H
题目简述
有一个含有0,1,-1的序列,其中的0代表可以换成 ± 1 \pm1 ±1,并同时满足K个条件。每一个条件由三个整数组成,分别是 A I , B I , C I A_{I},B_{I},C_{I} AI,BI,CI,意思是从下标为 A i A_{i} Ai的数到下标为 B i B_{i} Bi的数的总和,并且总和大于等于 C i C_{i} Ci。
如果有解,输出字典序最小的序列,否则的话输出 I m p o s s i b l e Impossible Impossible。
输入说明
第一行输入两个整数 N , K ( 1 ≤ N ≤ 100000 ; 0 ≤ K ≤ 100000 ) N,K(1\le N \le 100000; 0 \le K \le 100000) N,K(1≤N≤100000;0≤K≤100000),分别表示数列的长度与条件的数量。第二列包含 N N N个整数 P i ( − 1 ≤ P i ≤ 1 ) P_{i}(-1 \le P_{i} \le 1) Pi(−1≤Pi≤1),若 P i = 0 P_{i} = 0 Pi=0代表第 i i i个位置可以改变为 ± 1 \pm 1 ±1,反之则代表不能改变。接下来的是K列每一列包含三个整数 A i , B i , C i ( 1 ≤ A i ≤ B i ≤ N ; − N ≤ C i ≤ N ) A_{i},B_{i},C_{i}(1 \le A_{i} \le B_{i} \le N; -N \le C_{i} \le N) Ai,Bi,Ci(1≤Ai≤Bi≤N;−N≤Ci≤N)。
输出说明
如果有满足条件的数列存在,输出整个数列,反之输出 I m p o s s i b l e Impossible Impossible。
样例输入 1
3 2
0 0 0
1 2 2
2 3 -1
样例输出 1
1 1 -1
样例输入 2
3 2
0 -1 0
1 2 2
2 3 -1
样例输出 2
Impssible
解法
用树状数组的方法来解题。先将整个数列初始化为每个值为-1的情况。然后把所有能改能够更改的位置都记录下来。把 K K K行条件记录下来,并用他们的右界 B i B_{i} Bi作为比较条件从小到大排序,因为我们要用贪心的方法从后往前来把所有能改的-1改成1,知道所有条件都能够满足。计算连续和可以用树状数组或者线段树达到需求。记住每次将-1更改为1后,这个位置不能再被更改了。
该解法的时间复杂度是 O ( N + K ∗ l o g N ) O(N + K*logN) O(N+K∗logN)。
源代码
#include <bits/stdc++.h>
using namespace std;
const int SIZE = 1e5+5;
int BTree[SIZE];
bool flag[SIZE];
int arr[SIZE];
int n, k;
struct Node{
int l, r, num;
}fuck[SIZE];
bool cmp(const Node& a, const Node& b) {
return a.r < b.r;
}
int lowbit(int x) {
return x & -x;
}
int sum(int x) {
int ret = 0;
while(x > 0) {
ret += BTree[x];
x -= lowbit(x);
}
return ret;
}
void add(int x, int d) {
while(x <= n) {
BTree[x] += d;
x += lowbit(x);
}
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
if(arr[i] != 0) flag[i] = true;
if(arr[i] == 0) arr[i] = -1;
add(i, arr[i]);
}
bool ok = true;
for(int i = 0; i < k; i++) {
cin >> fuck[i].l >> fuck[i].r >> fuck[i].num;
}
sort(fuck, fuck+k, cmp);
int a, b, c;
for(int i = 0; i < k; i++) {
a = fuck[i].l, b = fuck[i].r, c = fuck[i].num;
int he = sum(b)-sum(a-1);
if(he < c) {
for(int j = b; j >= a && he < c; j--) {
if(!flag[j]) {
he += 2;
add(j, 2);
arr[j] = 1;
flag[j] = true;
}
}
}
if(he < c) ok = false;
}
if(ok) {
cout << arr[1];
for(int i = 2; i <= n; i++) {
cout << " " << arr[i];
}
cout << endl;
} else {
cout << "Impossible" << endl;
}
return 0;
}