# 线段树开新坑：kuangbin带你飞

## 写在最前面的废话

9月开头回家一波，重新填坑，= =，kuangbin带你飞的pdf，这才一半题，后面还有一波，蓝瘦，慢慢写吧，不写题怎么变的更强

## 单点更新

### A:hdu1166敌兵布阵：单点增减，区间sum

cmy曾经这题疯狂TLE

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
const int N=50500;
int tree[N],n,x,y;
string st;

while (k<=n){
tree[k]+=num;
k+=k&-k;
}
}

int sum=0;
while (k){
sum+=tree[k];
k-=k&-k;
}
return sum;
}

int main(){
int T;scanf("%d",&T);
for (int cas=1;cas<=T;cas++){
scanf("%d",&n);
memset(tree,0,sizeof(tree));
for (int i=1;i<=n;i++){
scanf("%d",&x);
}
scanf("\n");
printf("Case %d:\n",cas);
int k=0;
for (;cin>>st&&st[0]!='E';){
scanf("%d%d",&x,&y);
}
}
return 0;
} 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 7;

struct segmentTree
{
#define lc (t<<1)
#define rc (t<<1^1)
int sum[N], M;

inline void build(int n){
M = 1;
for (;M < n;) M <<= 1;
M--;
memset(sum, sizeof(sum), 0);
for (int i = 1+M; i <= n+M; i++){
scanf("%d", &sum[i]);
}
for (int t = M; t >= 1; t--){
sum[t] = sum[lc] + sum[rc];
}
}

for (sum[t+=M]+=x, t>>=1; t; t>>=1){
sum[t] = sum[lc] + sum[rc];
}
}

int query(int l, int r){
int ans = 0;
for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){
if (~l&1) ans += sum[l^1];
if ( r&1) ans += sum[r^1];
}
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _, n, x, y;
scanf("%d", &_);
for (int __ = 1; __<=_;__++){
printf("Case %d:\n", __);
scanf("%d", &n);
T.build(n);
getchar();
string st;
for (;cin >> st && st[0] != 'E';){
scanf("%d%d", &x, &y);
if (st[0] == 'A'){
}else if (st[0] == 'S'){
}else{
printf("%d\n", T.query(x, y));
}
}
}
}

### B:HDU 1754 I Hate It单点替换，区间rmq

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 8e5 + 7;

struct segmentTree
{
#define lc (t<<1)
#define rc (t<<1^1)
int ma[N], M;

inline void build(int n){
M = 1;
for (;M < n;) M <<= 1;
M--;
memset(ma, sizeof(ma), 0);
for (int i = 1+M; i <= n+M; i++){
scanf("%d", &ma[i]);
}
for (int t = M; t >= 1; t--){
ma[t] = max(ma[lc], ma[rc]);
}
}

void update(int t, int x){
for (ma[t+=M] = x, t>>=1; t; t>>=1){
ma[t] = max(ma[lc], ma[rc]);
}
}

int query(int l, int r){
int ans = 0;
for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){
if (~l&1) ans = max(ans, ma[l^1]);
if ( r&1) ans = max(ans, ma[r^1]);
}
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _, n, m, x, y;
for (;~scanf("%d%d", &n, &m);){
T.build(n);
string st;
for (;m--;){
cin >>st;
scanf("%d%d", &x, &y);
if (st[0] == 'U'){
T.update(x, y);
}else{
printf("%d\n", T.query(x, y));
}
}
}
}

### C:HDU 1394 Minimum Inversion Number 逆序对

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 7;

struct binaryIndexTree
{
int val[N], n;

inline void init(int n){
this->n = n;
memset(val, 0, sizeof(val));
}

inline void add(int k, int num){
for (;k <= n;){
val[k] += num;
k += k&-k;
}
}

inline int sum(int k){
int sum = 0;
for (;k;){
sum += val[k];
k -= k&-k;
}
return sum;
}
} T;

int arr[N], n;

int main()
{
//freopen("in.txt", "r", stdin);
for (;~scanf("%d", &n);){
T.init(n);
int sum = 0;
for (int i = 0; i < n; i++){
scanf("%d", &arr[i]);
arr[i]++;
sum += T.sum(n) - T.sum(arr[i] - 1);
}
int ans = sum;
for (int i = 0; i < n; i++){
sum += (n - arr[i]) - (arr[i] - 1);
ans = min(ans, sum);
}
printf("%d\n", ans);
}
}

### D HDU 2795 Billboard单点查询修改

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1^1
int val[N], M; // M: num of non-leaf nodes
// have an index of the array x
// x + M is the index of it in the tree

inline void build(int n, int w){
M = 1; while(M<n) M<<=1; M--;
// leaf nodes with values
for (int leaf = 1+M; leaf <= n+M; leaf++){
val[leaf] = w;
}
// leaf nodes which is null
for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
val[leaf] = 0;
}
// non-leaf nodes(include root)
for (int rt = M; rt >= 1; rt--){
val[rt] = max(val[lc], val[rc]);
}
}

inline void pushUp(int rt){
val[rt] = max(val[lc], val[rc]);
}

inline int query(int x, int rt){
if (rt > M){
val[rt] -= x;
return rt - M;
}
int ans = (val[lc] >= x) ? query(x, lc) : query(x, rc);
pushUp(rt);
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int n, h, w, x;
for (;~scanf("%d%d%d", &h, &w, &n);){
h = min(h, n);
T.build(h, w);
for (;n--;){
scanf("%d", &x);
if (T.val[1] < x) puts("-1");
else printf("%d\n", T.query(x, 1));
}
}
return 0;
}

### E POJ 2828 Buy Tickets单点查询修改

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;

int ans[N], pos[N], jump[N];

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1^1
int val[N], M; // M: num of non-leaf nodes
// have an index of the array x
// x + M is the index of it in the tree

inline void build(int n){
M = 1; while(M<n) M<<=1; M--;
// leaf nodes with values
for (int leaf = 1+M; leaf <= n+M; leaf++){
val[leaf] = 1;
}
// leaf nodes which is null
for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
val[leaf] = 0;
}
// non-leaf nodes(include root)
for (int rt = M; rt >= 1; rt--){
val[rt] = val[lc] + val[rc];
}
}

inline void pushUp(int rt){
val[rt] = val[lc] + val[rc];
}

inline void update(int pos, int jump, int rt){
if (rt > M){
val[rt]--;
ans[rt-M] = jump;
return;
}
if (val[lc] >= pos) update(pos, jump, lc);
else update(pos-val[lc], jump, rc);
pushUp(rt);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int n;
for (;~scanf("%d", &n);){
T.build(n);
for (int i = 1; i <= n; i++){
scanf("%d %d", &pos[i], &jump[i]);
pos[i]++;
}
for (int i = n; i >= 1; i--){
T.update(pos[i], jump[i], 1);
}
for (int i = 1; i < n; i++){
printf("%d ", ans[i]);
}
printf("%d\n", ans[n]);
}
return 0;
}

### F POJ 2886 Who Gets the Most Candies?反素数+单点操作

n个熊孩子每个人有个数字a[i]，首先k号熊孩子出圈，然后第k+a[i]个熊孩子出圈，一个环，可以绕很多圈，如果a[i]为正则顺时针数，反之逆时针，相当于一个变体的约瑟夫游戏，第i个出圈的熊孩子，有f[i]的得分，f[i]为i的因子个数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e7 + 7;
const LL INF = ~0LL;
const int prime[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

struct child{
char name[11];
int val;
inline void read(){scanf("%s %d\n", name, &val);}
}arr[N];

LL maxNum, ansPos, n;

void dfs(int dep, LL tmp, int num){
if (dep >= 16) return;
if (num > maxNum){
maxNum = num;
ansPos = tmp;
}
if (num == maxNum && ansPos > tmp) ansPos = tmp;
for (int i = 1; i < 63; i++){
if (n / prime[dep] < tmp) break;
dfs(dep+1, tmp *= prime[dep], num*(i+1));
}
}

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int val[N], M;

inline void build(int n){
M = 1; while(M<n) M<<=1; M--;
for (int leaf = 1+M; leaf <= n+M; leaf++) val[leaf] = 1;
for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++) val[leaf] = 0;
for (int rt = M; rt >= 1; rt--) val[rt] = val[lc] + val[rc];
}

inline int update(int pos, int rt){
val[rt]--;
if (rt > M) return rt - M;
if (val[lc] >= pos) return update(pos, lc);
else return update(pos-val[lc], rc);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int &mod = T.val[1];
for (LL k; ~scanf("%lld%lld\n", &n, &k);){
for (int i = 1; i <= n; i++) arr[i].read();
T.build(n);
ansPos = INF;
maxNum = 0;
dfs(0, 1, 1);

int pos = 0;
for (int i = 1; i <= ansPos; i++){
pos = T.update(k, 1);
//printf("k = %lld, pos = %d, mod = %d\n", k, pos, mod);
if (mod == 0) break;
if (arr[pos].val>0) k = (k-1 + arr[pos].val) % mod;
else k = ((k + arr[pos].val) % mod + mod) % mod;
if (k == 0) k = mod;
}
printf("%s %lld\n", arr[pos].name, maxNum);
}
return 0;
}

## 区间修改

### G HDU 1698 Just a Hook屠夫的钩

dota配图好评！！！

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5e6 + 7;

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M, sum[N], tag[N];
// 这里相对于常见的线段树，多了一个M，
// M的实际含义为非叶子节点的数量，
// 原数组索引为x，在线段树数组中的索引就是 M + x

// 因此，build可以改为自底向上的build
// n个实际有效的叶子节点，M+1-n个空值的叶子节点
inline void build(int n){
M = 1; while(M<n) M<<=1; M--;
memset(tag, 0, sizeof(tag));
// leaf nodes with values
for (int leaf = 1+M; leaf <= n+M; leaf++){
sum[leaf] = 1;
}
// leaf nodes which is null
for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
sum[leaf] = 0;
}
// non-leaf nodes(include root)
for (int rt = M; rt >= 1; rt--){
sum[rt] = sum[lc] + sum[rc];
}
}

inline void pushUp(int rt){
sum[rt] = sum[lc] + sum[rc];
}

inline void pushDown(int rt, int len){
if (!tag[rt]) return;
tag[lc] = tag[rc] = tag[rt];
sum[lc] = sum[rc] = tag[rt] * (len>>1);
tag[rt] = 0;
}

inline void update(int L, int R, int x, int l, int r, int rt){
//printf("update(%d, %d, %d, %d, %d, %d)\n", L, R, x, l, r, rt);
if (L <= l && r <= R){
tag[rt] = x;
sum[rt] = (r-l+1) * x;
return;
}
pushDown(rt, r-l+1);
int m = (l+r) >> 1;
if (L <= m) update(L, R, x, lson);
if (m <  R) update(L, R, x, rson);
pushUp(rt);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _, n, q, l, r, x;
scanf("%d", &_);
for (int __ = 1; __ <= _; __++){
scanf("%d%d", &n, &q);
T.build(n);
for (;q--;){
scanf("%d%d%d", &l, &r, &x);
T.update(l, r, x, 1, T.M+1, 1);
}
printf("Case %d: The total value of the hook is %d.\n", __, T.sum[1]);
}
return 0;
}

### H POJ 3468 A Simple Problem with Integers 区间修改和查询

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL N = 5e5 + 7;

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
LL M, sum[N], tag[N];
// 这里相对于常见的线段树，多了一个M，
// M的实际含义为非叶子节点的数量，
// 原数组索引为x，在线段树数组中的索引就是 M + x

// 因此，build可以改为自底向上的build
// n个实际有效的叶子节点，M+1-n个空值的叶子节点
inline void build(LL n){
M = 1; while(M<n) M<<=1; M--;
memset(tag, 0, sizeof(tag));
// leaf nodes with values
for (LL leaf = M+1; leaf <= n+M; leaf++){
scanf("%lld", &sum[leaf]);
}
// leaf nodes which is null
for (LL leaf = n+1+M; leaf <= (M<<1^1); leaf++){
sum[leaf] = 0;
}
// non-leaf nodes(include root)
for (LL rt = M; rt >= 1; rt--){
sum[rt] = sum[lc] + sum[rc];
}
}

inline void pushUp(LL rt){
sum[rt] = sum[lc] + sum[rc];
}

inline void pushDown(LL rt, LL len){
if (tag[rt] == 0) return;
tag[lc] += tag[rt];
tag[rc] += tag[rt];
sum[lc] += tag[rt] * (len>>1);
sum[rc] += tag[rt] * (len>>1);
tag[rt] = 0;
}

inline void update(LL L, LL R, LL x, LL l, LL r, LL rt){
//prLLf("update(%d, %d, %d, %d, %d, %d)\n", L, R, x, l, r, rt);
if (L <= l && r <= R){
tag[rt] += x;
sum[rt] += (r-l+1) * x;
return;
}
pushDown(rt, r-l+1);
LL m = (l + r) >> 1;
if (L <= m) update(L, R, x, lson);
if (m <  R) update(L, R, x, rson);
pushUp(rt);
}

LL query(LL L, LL R, LL l, LL r, LL rt){
if (L <= l && r <= R) return sum[rt];
pushDown(rt, r-l+1);
LL m = (l + r) >> 1;
LL ans = 0;
if (L <= m) ans += query(L, R, lson);
if (m <  R) ans += query(L, R, rson);
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
LL n, q, l, r, x;
char ch;
for (;~scanf("%lld%lld", &n, &q);){
T.build(n);
for (;q--;){
getchar();
scanf("%c%lld%lld", &ch, &l, &r);
if (ch == 'Q'){
printf("%lld\n", T.query(l, r, 1, T.M+1, 1));
} else {
scanf("%lld", &x);
T.update(l, r, x, 1, T.M+1, 1);
}
}
}
return 0;
}


### I POJ 2528 Mayor’s posters 离散化姿势比较清奇

by cww97

and，卡了两个小时是因为

//for (int i = 1; i <= A; i++) {
//  x[a[i]] = i;//啊啊啊啊啊啊啊啊啊啊啊啊啊啊
//printf("x[%d] = %d\n", a[i], i);
//}

T.build(A);
for (int i = 1; i <= n; i++){
int L = lower_bound(a+1, a+A+1, l[i]) - a;//x[l[i]]
int R = lower_bound(a+1, a+A+1, r[i]) - a;//x[r[i]]
//printf("(%d, %d)\n", L, R);
T.update(L, R, i, 1, T.M+1,1);
}

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 7;

int l[N], r[N], n;
int a[N], A, x[N];
bool vis[N];
int ans;

struct segmentTree
{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M, col[N];

inline void build(int n){
M = 1; while(M<n)M<<=1; M--;
memset(col, 0, sizeof(col));
}

inline void pushDown(int rt){
if (col[rt] == 0) return;
col[lc] = col[rc] = col[rt];
col[rt] = 0;
}

inline void update(int L, int R, int x, int l, int r, int rt){
if (L <= l && r <= R){
col[rt] = x;
return;
}
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) update(L, R, x, lson);
if (m <  R) update(L, R, x, rson);
}

inline int query(int rt){
if (col[rt] > 0) {
if (vis[col[rt]]) return 0;
vis[col[rt]] = 1;
return 1;
}
if (rt > M) return 0;
int ans = 0;
ans += query(lc);
ans += query(rc);
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _;
scanf("%d", &_);
for (;_--;){
scanf("%d", &n);
A = 0;
for (int i = 1; i <= n; i++){
scanf("%d%d", &l[i], &r[i]);
a[++A] = l[i];
a[++A] = r[i];
}
sort(a + 1, a + A+1);
A = unique(a + 1, a + A+1) - (a + 1);
for (int i = A; i > 1; i--){
if (a[i-1] + 1 < a[i]) a[++A] = a[i-1] + 1;
}
sort(a + 1, a + A+1);

T.build(A);
for (int i = 1; i <= n; i++){
int L = lower_bound(a+1, a+A+1, l[i]) - a;
int R = lower_bound(a+1, a+A+1, r[i]) - a;
T.update(L, R, i, 1, T.M+1,1);
}
ans = 0;
memset(vis, 0, sizeof(vis));
printf("%d\n", T.query(1));
}
return 0;
}

### J POJ 3225 Help with Intervals 双标记线段树

1.关于集合运算的推导规约，知道集合是什么东西就一定会推导！

U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换


2.倍化区间处理开闭区间的问题。因为普通的线段树实际处理的并非真正的区间，而是一系列点，相当于处理一个向量。这个问题需要处理的是真正的区间，所以应该有一个主导思想就是，把区间点化！不知哪位大牛搞了一个倍增区间出来，实在佩服！对于待处理区间a,b，对其边界均乘2。若区间左开则对左界值+1，若区间右开，则对右界-1！

如：[2,3]会倍增为[4,6]，[2,3)会倍增为[4,5]，（2,3]会倍增为[5,6]，(2,3)将倍增为[5,5]，我们这时可以看到，对于普通线段树无法处理的线段如(x,x+1)将被点化为[2*x+1,2*x+1]！这个问题得到比较完美的解决


wa了，lj跟我抱怨：你就不能老老实实写个双标记线段树吗

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 131072 + 7;
int ans[N];

struct segTree{
#define lc rt<<1
#define rc rt<<1^1
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int tree[N<<1], lazy[N<<1];

inline void build(){
memset(lazy, 0, sizeof(lazy));
memset(tree, 0, sizeof(tree));
}

inline void pushDown(int rt){
if (tree[rt] != -1){ // -1: mixture
tree[lc] = tree[rc] = tree[rt];
lazy[lc] = lazy[rc] = 0;
}
if (lazy[rt]){
if (tree[lc] != -1) tree[lc] ^= 1;
else lazy[lc] ^= 1;
if (tree[rc] != -1) tree[rc] ^= 1;
else lazy[rc] ^= 1;
lazy[rt] = 0;
}
tree[rt] = -1;
}

void setval(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R) {
tree[rt] = val;
lazy[rt] = 0;
return;
}
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) setval(L, R, val, lson);
if (m <  R) setval(L, R, val, rson);
}

void invert(int L, int R, int l, int r, int rt){
if (L <= l && r <= R){
if (tree[rt] != -1) tree[rt] ^= 1;
else lazy[rt] ^= 1;
return;
}
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) invert(L, R, lson);
if (m <  R) invert(L, R, rson);
}

void query(int l, int r, int rt){
if (l == r){ // leaf
ans[l] = tree[rt] ^ lazy[rt];
return;
}
pushDown(rt);
int m = (l + r) >> 1;
query(lson);
query(rson);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
char op, lseg, rseg;
int l, r, n = 131072;
T.build();
for (;~scanf("%c %c%d,%d%c\n", &op, &lseg, &l, &r, &rseg);){
l <<= 1, r <<= 1;
if (lseg == '(') l++;
if (rseg == ')') r--;
//printf("--------> %c [%d, %d]\n", op, l, r);
if (l > r){
if (op == 'I' || op == 'C'){
T.setval(0, n, 0, 0, n, 1);
}
} else if (op == 'U'){ // S = S | T
T.setval(l, r, 1, 0, n, 1);
} else if (op == 'I'){ // S = S & T
if (l > 0) T.setval(0, l-1, 0, 0, n, 1);
if (r < n) T.setval(r+1, n, 0, 0, n, 1);
} else if (op == 'D'){ // S = S - T
T.setval(l, r, 0, 0, n, 1);
} else if (op == 'C'){ // S = T - S
T.invert(l, r, 0, n, 1);
if (l > 0) T.setval(0, l-1, 0, 0, n, 1);
if (r < n) T.setval(r+1, n, 0, 0, n, 1);
} else { // op == 'S': S = S^T = (S-T)|(T-S)
T.invert(l, r, 0, n, 1);
}
}
T.query(0, n, 1);
bool haveAns = 0, haveOne = 0;
for (int i = 0; i <= n; i++){
if (!haveOne && ans[i]){
if (haveAns) putchar(' ');
haveAns = haveOne = 1;
putchar(i&1 ? '(' : '[');
printf("%d,", i >> 1);
} else if (haveOne && !ans[i]){
printf("%d", i >> 1);
putchar((i-1)&1 ? ')' :']');
haveOne = 0;
}
}
if (!haveAns) puts("empty set");
else puts("");
return 0;
}

### K POJ 1436 Horizontally Visible Segments 区间染色

8000*8000/1024/1024 = 61MB

if (reach[k][i] && reach[k][j]) ans++;

cpu访问高速缓存里的数据，不直接访问内存里的，所以，这个数组太大(60MB)没法整个丢进高速缓存里，只能一次丢个几行，前一种写法，第三重循环只会访问数组的i和j行，第三重循环每次都是缓存命中的，不会向内存再发请求，而后一种写法，k没变化一次，缓存就不命中一次，就好再装填缓存，然后就TLE了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 8007;

struct line{
int l, r, x, id;
scanf("%d%d%d", &l, &r, &x);
id = i, l <<= 1, r <<= 1;
}
bool operator < (const line &b) const {
return x < b.x;
}
} lines[N];

bool reach[N][N];

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int tree[N*8], n;

inline void build(){
n = 8000 * 2; // length of tree
memset(tree, 0, sizeof(tree));
}

inline void pushDown(int rt){
if (!tree[rt]) return;
tree[lc] = tree[rc] = tree[rt];
tree[rt] = 0;
}

void update(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R){
tree[rt] = val;
return;
}
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
}

void query(int L, int R, int id, int l, int r, int rt){
if (tree[rt]){
reach[tree[rt]][id] = 1;
return;
}
if (l == r) return;
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) query(L, R, id, lson);
if (m <  R) query(L, R, id, rson);
}

inline void query(int l, int r, int id){
query(l, r, id, 0, n, 1);
}
inline void update(int l, int r, int val){
update(l, r, val, 0, n, 1);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _, n;
scanf("%d", &_);
for (; _--;){
scanf("%d", &n);
for (int i = 1; i <= n; i++) lines[i].read(i);
sort(lines + 1, lines + n + 1);
T.build();
memset(reach, 0, sizeof(reach));
for (int i = 1; i <= n; i++){
T.query(lines[i].l, lines[i].r, i);
T.update(lines[i].l, lines[i].r, i);
}
int ans = 0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++) if (reach[i][j]){
for (int k = 1; k <= n; k++){
if (reach[i][k] && reach[j][k]) ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}


### L POJ 2991 Crane 计算几何

[xy][cos(a)sin(a)sin(a)cos(a)]=[xy]

struct vec{
double x, y, a, lazy;// a is the angle between i and i-1
};

update之后再更新vec[s+1] = a

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 4e4 + 7;
const double PI = acos(-1.0);
const double EPS = 1e-8;
int arr[N];

struct vec{
double x, y, a, lazy;// a is the angle between i and i-1
vec (){}
vec (double q, double w, double e, double r):x(q), y(w), a(e), lazy(r){}
vec operator + (const vec &V) const { // only no-leaf nodes get from +
return vec(x + V.x, y + V.y, a, 0); // so last 2 numbers no important
}
inline void tag(const double &ang){
double ox = x, oy = y; // old x&y
x = ox * cos(-ang) - oy * sin(-ang);// rotate
y = ox * sin(-ang) + oy * cos(-ang);
lazy += ang;
}
inline void print(){ // 0.0 YouYa
double px = fabs(x)<EPS ? 0 : x; // I don't want to see "-0.00"
double py = fabs(y)<EPS ? 0 : y;
printf("%.2lf %.2lf\n", px, py);
}
};

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M;
vec tree[N];

inline void build(const int &n){
M=1; for(;M<n;)M<<=1; if(M>1)M--;
memset(tree, 0, sizeof tree);
for (int len, i = 1; i <= M+1; i++){
tree[i+M] = vec(0, i<=n ? arr[i] : 0, PI, 0);
}
for (int rt = M; rt >= 1; rt--) {
tree[rt] = tree[lc] + tree[rc];
}
}

inline void pushDown(int rt){
if (fabs(tree[rt].lazy) < EPS) return;
tree[lc].tag(tree[rt].lazy);
tree[rc].tag(tree[rt].lazy);
tree[rt].lazy = 0;
}

void update(int L, int R, double val, int l, int r, int rt){
if (L <= l && r <= R){tree[rt].tag(val); return;}
pushDown(rt);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
tree[rt] = tree[lc] + tree[rc];
}
inline void update(int l, int r, double val){
update(l, r, tree[l+M].a - val, 1, M+1, 1);
tree[l+M].a = val;//attention: val is the ang between l-1 and l
tree[1].print();
}
} T; // sometimes we need undef here

int main(){
//freopen("in.txt", "r", stdin);
bool firstT = 1;
for (int n, q; ~scanf("%d%d", &n, &q);){
if (!firstT) puts(""); firstT = 0;
for (int i = 1; i <= n; i++) scanf("%d", arr + i);
T.build(n);
for (int s, a; q--;){
scanf("%d%d", &s, &a);
T.update(s+1, n, PI * a / 180);
}
}
return 0;
}

## 区间合并

### M POJ 3667 Hotel 区间合并

1 a:询问是不是有连续长度为 a 的空房间,有的话住进最左边

2 a b:将[a,a+b-1]的房间清空

    // have relation with int main
inline void update(int l, int r, int val){
update(l, r, val, 1, M+1, 1);
}
inline int query(int len){
return query(len, 1, M+1, 1);
}

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 65536 * 2 + 7;

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M;
int lsum[N], msum[N], rsum[N], lazy[N];

inline void build(const int &n){
M=1; for(;M<n;) M<<=1; if(M>1)M--;
memset(lazy,-1, sizeof lazy);
for (int i = 1; i <= M+1; i++){
lsum[i+M] = msum[i+M] = rsum[i+M] = i<=n ? 1 : 0;
}
for (int rt = M; rt >= 1; rt--) {
lsum[rt] = msum[rt] = rsum[rt] = msum[lc] + msum[rc];
}
}

inline void pushUp(int rt, int len){
lsum[rt] = lsum[lc];
rsum[rt] = rsum[rc];
if (lsum[rt] == len>>1) lsum[rt] += lsum[rc];
if (rsum[rt] == len>>1) rsum[rt] += rsum[lc];
msum[rt] = max(msum[lc], msum[rc]);
msum[rt] = max(msum[rt], rsum[lc] + lsum[rc]);
}

inline void pushDown(int rt, int len){
if (lazy[rt] == -1) return;
lazy[lc] = lazy[rc] = lazy[rt];
lsum[lc] = msum[lc] = rsum[lc] = lazy[rt] ? 0 : len>>1;
lsum[rc] = msum[rc] = rsum[rc] = lazy[rt] ? 0 : len>>1;
lazy[rt] = -1;
}

void update(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R){
lsum[rt] = msum[rt] = rsum[rt] = val ? 0 : r-l+1;
lazy[rt] = val;
return;
}
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
pushUp(rt, r-l+1);
}
int query(int len, int l, int r, int rt){
if (l == r) return l;
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (msum[lc] >= len) return query(len, lson);
else if (rsum[lc] + lsum[rc] >= len) return m-rsum[lc]+1;
else if (msum[rc] >= len) return query(len, rson);
return 0;
}
// have relation with int main
inline void update(int l, int r, int val){
update(l, r, val, 1, M+1, 1);
}
inline int query(int len){
return query(len, 1, M+1, 1);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
for (int n, q; ~scanf("%d%d", &n, &q);){
T.build(n);
for (int op, pos, len; q--;){
scanf("%d", &op);
if (op == 1){ // query
scanf("%d", &len);
printf("%d\n", pos = T.query(len));
if (pos) T.update(pos, pos+len-1, 1);
} else { // set
scanf("%d%d", &pos, &len);
T.update(pos, pos+len-1, 0);
}
}
}
return 0;
}

### N HDU 3308 LCIS 最大连续上升子序列

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 262144 + 7;
int arr[N];

struct ZKWsegTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M;
int lnum[N], rnum[N];
int lsum[N], msum[N], rsum[N];

inline void pushUp(int rt, int len){
lnum[rt] = lnum[lc], rnum[rt] = rnum[rc];
lsum[rt] = lsum[lc], rsum[rt] = rsum[rc];
msum[rt] = max(msum[lc], msum[rc]);
if (rnum[lc] < lnum[rc]){
if (lsum[rt] == len>>1) lsum[rt] += lsum[rc];
if (rsum[rt] == len>>1) rsum[rt] += rsum[lc];
msum[rt] = max(msum[rt], rsum[lc] + lsum[rc]);
}
}

inline void build(const int &n){
M=1;for(;M<n;)M<<=1;if(M>1)M--;
for (int i = 1; i <= M+1; i++){
lsum[i+M] = msum[i+M] = rsum[i+M] = 1;
lnum[i+M] = rnum[i+M] = i<=n ? arr[i] : 0;
}
for (int len = 2, rt = M; rt >= 1; rt--) {
pushUp(rt, len);
if ((rt&(rt-1)) == 0) len <<= 1;
}
}

inline void update(int pos, int val){
lnum[pos+=M] = rnum[pos] = val;
for (int len=2, rt = pos>>1; rt; rt>>=1, len<<=1){
pushUp(rt, len);
}
}

int query(int L, int R, int l, int r, int rt){
if (L <= l && r <= R) return msum[rt];
int ans = 0;
int m = (l + r) >> 1;
if (L <= m) ans = max(ans, query(L, R, lson));
if (m <  R) ans = max(ans, query(L, R, rson));
if (rnum[lc] < lnum[rc] && L <= m && m < R){
ans = max(ans, min(m-L+1, rsum[lc])
+ min(R - m, lsum[rc]));
}
return ans;
}

inline int query(int l, int r){
return query(l, r, 1, M+1, 1);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _; scanf("%d", &_);
char op[3];
for (int n, q; _--;){
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", arr + i);
T.build(n);
for (int x, y; q--;){
scanf("%s%d%d", op, &x, &y);
if (op[0] == 'U') T.update(x+1, y);
else printf("%d\n", T.query(x+1, y+1));
}
}
return 0;
}

### O HDU 3397区间合并区间赋值区间取反

lazy更新后清空vert
vert更新的时候^=1即可

lsum[][2], msum[][2], rsum[][2]

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 262144 + 7;
int arr[N];

// 0: 将区间[a,b]之间的数全部置为0
// 1: 将区间[a,b]之间的数全部置为1
// 2: 将区间[a,b]之间的 1->0  0->1
// 3: 求区间[a,b]之间1的个数
// 4: 求区间[a,b]之间1的最长连续长度

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M; // number of no-leaf nodes
int lsum[N][2], msum[N][2], rsum[N][2], nsum[N]; // values
int vert[N], lazy[N]; // tags

// 赋值操作，结束后记得清空vert标记
inline void setTag(const int &rt, const int &val, const int &len){
nsum[rt] = val ? len : 0;
lsum[rt][0] = msum[rt][0] = rsum[rt][0] = val ? 0 : len;
lsum[rt][1] = msum[rt][1] = rsum[rt][1] = val ? len : 0;
lazy[rt] = val;
vert[rt] = 0;
}

// 对rt节点进行取反操作，swap 0 和 1 的值
inline void vertTag(const int &rt, const int &len){
nsum[rt] = len - nsum[rt];
swap(lsum[rt][0], lsum[rt][1]);
swap(msum[rt][0], msum[rt][1]);
swap(rsum[rt][0], rsum[rt][1]);
vert[rt] ^= 1;
}

//区间合并的pushUp大体都这么写
inline void pushUp(const int &rt, const int &len){
nsum[rt] = nsum[lc] + nsum[rc];
for (int i = 0; i < 2; i++){
lsum[rt][i] = lsum[lc][i];
rsum[rt][i] = rsum[rc][i];
if (lsum[rt][i] == len>>1) lsum[rt][i] += lsum[rc][i];
if (rsum[rt][i] == len>>1) rsum[rt][i] += rsum[lc][i];
msum[rt][i] = max(msum[lc][i], msum[rc][i]);
msum[rt][i] = max(msum[rt][i], rsum[lc][i] + lsum[rc][i]);
}
}

// 优先lazy标记，但是不要干扰vert标记
// vert的时候进入vertTag必须保证lazy==-1
inline void pushDown(const int &rt, const int &len){
if (lazy[rt] != -1){
setTag(lc, lazy[rt], len>>1);
setTag(rc, lazy[rt], len>>1);
vert[lc] = vert[rc] = 0;
}
if (vert[rt]){
if (lazy[lc] != -1) setTag(lc, lazy[lc]^1, len>>1);
else vertTag(lc, len>>1);
if (lazy[rc] != -1) setTag(rc, lazy[rc]^1, len>>1);
else vertTag(rc, len>>1);
vert[rt] = 0;
}
lazy[rt] = -1;
}

inline void build(const int &n){
M=1; for(;M<n;) M<<=1; if(M>1)M--;
memset(vert, 0, sizeof vert);
memset(lazy,-1, sizeof lazy);
for (int i = 1; i <= M+1; i++){
nsum[i+M] = i<=n ? arr[i] : 0;
lsum[i+M][0] = msum[i+M][0] = rsum[i+M][0] = i<=n ?!arr[i] : 0;
lsum[i+M][1] = msum[i+M][1] = rsum[i+M][1] = i<=n ? arr[i] : 0;
}
for (int rt = M, len = 2; rt >= 1; rt--) {
pushUp(rt, len);
if ((rt&(rt-1)) == (!rt)) len <<= 1;//O(1)判断2的整数次幂,dep--
}
}

void update(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R){
if (val != -1) setTag(rt, val, r-l+1);
else { // invert
if (lazy[rt] != -1) setTag(rt, lazy[rt]^1, r-l+1);
else vertTag(rt, r-l+1);
}
return;
}
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
pushUp(rt, r-l+1);
}

int sum(int L, int R, int l, int r, int rt){
if (L <= l && r <= R) return nsum[rt];
pushDown(rt, r-l+1);
int m = (l + r) >> 1, ans = 0;
if (L <= m) ans += sum(L, R, lson);
if (m <  R) ans += sum(L, R, rson);
return ans;
}

int query(int L, int R, int l, int r, int rt){
if (L <= l && r <= R) return msum[rt][1];
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
// 区间合并的查询操作
int ans = min(m-L+1, rsum[lc][1]) + min(R - m, lsum[rc][1]);
if (L <= m) ans = max(ans, query(L, R, lson));
if (m <  R) ans = max(ans, query(L, R, rson));
return ans;
}

// have relation with int main, out API
inline void setval(const int &l, const int &r, const int &val){
update(l, r, val, 1, M+1, 1);
}
inline void invert(const int &l, const int &r){
update(l, r,  -1, 1, M+1, 1);
}
inline int sum(const int &l, const int &r){
return sum(l, r, 1, M+1, 1);
}
inline int query(const int &l, const int &r){ // continus
return query(l, r, 1, M+1, 1);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
int _; scanf("%d", &_);
for (int n, q; _--;){
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", arr + i);
T.build(n);
for (int op, l, r; q--;){
scanf("%d%d%d", &op, &l, &r);
l++, r++;
if (op == 0) T.setval(l, r, 0);
else if (op == 1) T.setval(l, r, 1);
else if (op == 2) T.invert(l, r);
else if (op == 3) printf("%d\n", T.sum(l, r));
else printf("%d\n", T.query(l, r));
}
}
return 0;
}

### P HDU 2871内存管理 vector真是神奇

upper_bound和lower_bound有点抽风，自己手写一个

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
using namespace std;
typedef pair <int, int> P;
const int N = 65536 * 2 + 7;

vector <P> G;
vector <P>::iterator it;
inline void printG(){
for (int i = 0; i < G.size(); i++){
printf("\t\tG[%d] = [%d, %d]\n", i, G[i].fi, G[i].se);
}
}

int Search(int l, int r, int val){ // lower_bound
for (int mid; l < r;){
mid = (l + r) >> 1;
if (G[mid].fi <= val) l = mid + 1;
else r = mid;
}
return l;
}

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M, n;
int lsum[N], msum[N], rsum[N], lazy[N];
// for this problem

inline void build(const int &n){
this->n = n;
M=1; for(;M<n;) M<<=1; if(M>1)M--;
memset(lazy,-1, sizeof lazy);
for (int i = 1; i <= M+1; i++){
lsum[i+M] = msum[i+M] = rsum[i+M] = i<=n ? 1 : 0;
}
for (int rt = M; rt >= 1; rt--) {
lsum[rt] = msum[rt] = rsum[rt] = msum[lc] + msum[rc];
}
G.clear(); // holy, exiting STL
}

inline void pushUp(int rt, int len){
lsum[rt] = lsum[lc];
rsum[rt] = rsum[rc];
if (lsum[rt] == len>>1) lsum[rt] += lsum[rc];
if (rsum[rt] == len>>1) rsum[rt] += rsum[lc];
msum[rt] = max(msum[lc], msum[rc]);
msum[rt] = max(msum[rt], rsum[lc] + lsum[rc]);
}

inline void pushDown(int rt, int len){
if (lazy[rt] == -1) return;
lazy[lc] = lazy[rc] = lazy[rt];
lsum[lc] = msum[lc] = rsum[lc] = lazy[rt] ? 0 : len>>1;
lsum[rc] = msum[rc] = rsum[rc] = lazy[rt] ? 0 : len>>1;
lazy[rt] = -1;
}

void update(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R){
lsum[rt] = msum[rt] = rsum[rt] = val ? 0 : r-l+1;
lazy[rt] = val;
return;
}
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
pushUp(rt, r-l+1);
}

int query(int len, int l, int r, int rt){
if (l == r) return l;
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (msum[lc] >= len) return query(len, lson);
else if (rsum[lc] + lsum[rc] >= len) return m-rsum[lc]+1;
else if (msum[rc] >= len) return query(len, rson);
return 0;
}

// have relation with int main
inline void Reset(){
update(1, n, 0, 1, M+1, 1);
G.clear();
puts("Reset Now");
}

inline void New(const int &len){
if (msum[1] < len) puts("Reject New");
else {
int pos = query(len, 1, M+1, 1);
update(pos, pos+len-1, 1, 1, M+1, 1);
printf("New at %d\n", pos);
it = upper_bound(G.begin(), G.end(), P(pos, pos));
G.insert(it, P(pos, pos + len -1));
}
}

inline void Free(const int &val){
int p = Search(0, G.size(), val) - 1;
//printf("    debug: p = %d, [%d, %d]\n", p, G[p].l, G[p].r);
//printG();
if (p == -1 || G[p].se < val) puts("Reject Free");
else {
update(G[p].fi, G[p].se, 0, 1, M+1, 1);
printf("Free from %d to %d\n", G[p].fi, G[p].se);
G.erase(G.begin() + p);
//printG();
}
}

inline void Get(const int &rnk){
if (rnk > G.size()) puts("Reject Get");
else printf("Get at %d\n", G[rnk-1].fi);
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
char op[9];
for (int n, q; ~scanf("%d%d", &n, &q);){
T.build(n);
for (int x; q--;){
scanf("%s", op);
if (op[0] == 'R') T.Reset();
else {
scanf("%d", &x);
if (op[0] == 'N') T.New(x);
else if (op[0] == 'F') T.Free(x);
else T.Get(x);
}
}
puts("");
}
return 0;
}

vector似乎比想象中的要快不少，这个vector的写法明显感觉不清真，

### Q HDU 1540 地道战 似乎都是单点操作

for循环更方便^-^

#include <cmath>
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 65536 * 2 + 7;
stack <int> S;

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M;
int lsum[N], msum[N], rsum[N];

inline void pushUp(int rt, int len){
lsum[rt] = lsum[lc];
rsum[rt] = rsum[rc];
if (lsum[rt] == len>>1) lsum[rt] += lsum[rc];
if (rsum[rt] == len>>1) rsum[rt] += rsum[lc];
msum[rt] = max(msum[lc], msum[rc]);
msum[rt] = max(msum[rt], rsum[lc] + lsum[rc]);
}

inline void build(const int &n){
M=1; for(;M<n;) M<<=1; if(M>1)M--;
for (int i = 1; i <= M+1; i++){
lsum[i+M] = msum[i+M] = rsum[i+M] = i<=n ? 1 : 0;
}
for (int rt = M, len = 2; rt >= 1; rt--) {
pushUp(rt, len);
if ((rt&(rt-1)) == !rt) len <<= 1;
}
}

void update(int &pos, const int &val){
lsum[pos+=M] = msum[pos] = rsum[pos] = val;
for (int rt = pos>>1, len = 2; rt; rt>>=1, len <<= 1){
pushUp(rt, len);
}
}

int query(const int &pos){
int ans = msum[pos+M];
if (!ans) return 0;
bool fromR = (pos + M) & 1;
for (int rt=(pos+M)>>1, l=pos, r=pos; rt; fromR=rt&1, rt>>=1){
if (fromR){
if (lsum[rc]==ans && ans>=pos-l+1) ans += rsum[lc];
l -= (r - l + 1);
} else {
if (rsum[lc]==ans && ans>=r-pos+1) ans += lsum[rc];
r += (r - l + 1);
}
}
return ans;
}
} T;

int main(){
//freopen("in.txt", "r", stdin);
char op[7];
for (int n, q; ~scanf("%d%d", &n, &q);){
T.build(n);
for (;!S.empty();) S.pop();
for (int pos; q--;){
scanf("%s", op);
if (op[0] == 'R') {
pos = S.top(); S.pop();
T.update(pos, 1);
} else {
scanf("%d", &pos);
if (op[0] == 'Q') printf("%d\n", T.query(pos));
else {
S.push(pos);
T.update(pos, 0);
}
}
}
}
return 0;
}

### R CodeForces 46D Parking Lot 板子稍微改改

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
using namespace std;
typedef pair<int, int> P;
const int N = 65536 * 2 * 2 + 7;

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M;
int lsum[N], msum[N], rsum[N], lazy[N];

inline void pushUp(int rt, int len){
lsum[rt] = lsum[lc];
rsum[rt] = rsum[rc];
if (lsum[rt] == len>>1) lsum[rt] += lsum[rc];
if (rsum[rt] == len>>1) rsum[rt] += rsum[lc];
msum[rt] = max(msum[lc], msum[rc]);
msum[rt] = max(msum[rt], rsum[lc] + lsum[rc]);
}

inline void pushDown(int rt, int len){
if (lazy[rt] == -1) return;
lazy[lc] = lazy[rc] = lazy[rt];
lsum[lc] = msum[lc] = rsum[lc] = lazy[rt] ? 0 : len>>1;
lsum[rc] = msum[rc] = rsum[rc] = lazy[rt] ? 0 : len>>1;
lazy[rt] = -1;
}

inline void build(const int &n){
M=1; for(;M<n;) M<<=1; if(M>1)M--;
memset(lazy,-1, sizeof lazy);
for (int i = 1; i <= M+1; i++){
lsum[i+M] = msum[i+M] = rsum[i+M] = i<=n ? 1 : 0;
}
for (int rt = M, len = 2; rt >= 1; rt--) {
pushUp(rt, len);
if ((rt&(rt-1)) == (!rt)) len <<= 1;
}
}

void update(int L, int R, int val, int l, int r, int rt){
if (L <= l && r <= R){
lsum[rt] = msum[rt] = rsum[rt] = val ? 0 : r-l+1;
lazy[rt] = val;
return;
}
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (L <= m) update(L, R, val, lson);
if (m <  R) update(L, R, val, rson);
pushUp(rt, r-l+1);
}

int query(int len, int l, int r, int rt){
if (l == r) return l;
pushDown(rt, r-l+1);
int m = (l + r) >> 1;
if (msum[lc] >= len) return query(len, lson);
else if (rsum[lc] + lsum[rc] >= len) return m - rsum[lc] + 1;
else if (msum[rc] >= len) return query(len, rson);
return 0;
}

// have relation with int main
inline void update(const int &l, const int &r, const int &val){
update(l, r, val, 1, M+1, 1);
}
inline int query(const int &len){
return query(len, 1, M+1, 1);
}
} T;

P car[111];

int main(){
//freopen("in.txt", "r", stdin);
for (int n, b, f, q; ~scanf("%d%d%d%d", &n, &b, &f, &q);){
n += b + f;
T.build(n);
for (int op, x, pos, i = 1; i <= q; i++){
scanf("%d%d", &op, &x);
if (op == 1){ // query
if (T.msum[1] < b + x + f) puts("-1");
else {
pos = T.query(b + x + f);
car[i] = P(pos + b, pos + b + x - 1);
printf("%d\n", pos - 1);
T.update(car[i].fi, car[i].se, 1);
}
} else T.update(car[x].fi, car[x].se, 0);

}
}
return 0;
}

## 扫描线

### S HDU 1542 Atlantis矩形面积并

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL N = 9999;

struct Seg{
double l, r, h;  // height
int s;  // status
Seg(){}
Seg(double x, double y, double z, int w): l(x), r(y), h(z), s(w){}
bool operator < (const Seg & b) const {return h < b.h;}
} seg[N];
double ux[N];
int X, S;  // top of seg[] & ux[]

struct segTree{
#define lc (rt<<1)
#define rc (rt<<1^1)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1^1
int M, cnt[N];
double sum[N];

inline void build(int n){
M=1; while(M<n)M<<=1; if(M>1)M--;
memset(sum, 0, sizeof sum);
memset(cnt, 0, sizeof cnt);
}

inline void pushUp(int rt, int l, int r){
if (cnt[rt]) sum[rt] = ux[r+1] - ux[l];
else sum[rt] = l==r ? 0 : sum[lc] + sum[rc];
}

void update(int L, int R, int x, int l, int r, int rt){
if (L <= l && r <= R){
cnt[rt] += x;
pushUp(rt, l, r);
return;
}
LL m = (l + r) >> 1;
if (L <= m) update(L, R, x, lson);
if (m <  R) update(L, R, x, rson);
pushUp(rt, l, r);
}

// for int main
inline void update(int l, int r, int val){
update(l, r, val, 1, M+1, 1);
}
} T;

int Search(double key, int l, int r, double ux[]){
for (; l <= r;){
int m = (l + r) >> 1;
if (ux[m] == key) return m;
if (ux[m] < key) l = m + 1;
else r = m -1;
}
return -1;
}

int main(){
//freopen("in.txt", "r", stdin);
for (int n, _ = 1; ~scanf("%d", &n) && n;){
printf("Test case #%d\n", _++);
X = S = 0;
for (int i = 1; i <= n; i++){
double l, low, r, high;
scanf("%lf%lf%lf%lf", &l, &low, &r, &high);
ux[++X] = l;
ux[++X] = r;
seg[++S] = Seg(l, r, low, 1);
seg[++S] = Seg(l, r, high, -1);
}
sort(seg + 1, seg + S+1);
sort(ux + 1, ux + X+1);
X = unique(ux + 1, ux + X +1) - ux - 1;
ux[X+1] = ux[X];
T.build(X);
double ans = 0;
for (int i = 1; i < S; i++){
int l = Search(seg[i].l, 1, X, ux);
int r = Search(seg[i].r, 1, X, ux) - 1;
T.update(l, r, seg[i].s);
ans += T.sum[1] * (seg[i+1].h - seg[i].h);
}
printf("Total explored area: %.2lf\n\n", ans);
}
return 0;
}