Jeanny
寂兮,寥兮,独立不改,周行而不殆

&st表

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int n,q,l,r,a[100005],f[100005][20];
int main(){
    scanf("%d%d",&n,&q);
    for(int i = 1; i <= n; i++){
        scanf("%d",&a[i]);
        f[i][0] = a[i];
    }
    int p = log2(n);
    cout<<"p: "<<p<<endl;
    for(int j = 1; j <= p; j++){
        //f[i][4] 到达 i + 2^4 - 1
        for(int i = 1; i + (1<<j) - 1 <= n; i++){
            f[i][j] = max(f[i][j-1], f[i + (1<<(j-1))][j-1]);
        }
    }

    for(int i = 1; i <= q; i++){
        scanf("%d%d",&l,&r);//  [l, l + 2^s - 1] 和 [r - 2^s +1, r]
        int j = log2(r - l + 1);// l + 2^s - 1 = r
        printf("%d\n",max(f[l][j],f[r - (1<<j) + 1][j]));
    }
    return 0;
}
/*
9 2
13 2 -6 10 9 -12 -4 2 19
1 8
5 6
*/

 

 

P2880 [USACO07JAN]Balanced Lineup G

忠诚 

&数状数组

[USACO10FEB]Slowing down G

 

&线段树

1.单点修改,区间查询  luogu3374

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
// #define int long long
#define ll long long
using namespace std;
const int mxn = 1e6 + 5;
ll n, m;
struct Tree {
    int l, r;
    ll sum, gcd;
} tree[mxn * 4];
ll a[mxn], b[mxn];
void pushup(int rt) { tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum; }
void build(int rt, int l, int r) {
    tree[rt].l = l, tree[rt].r = r;
    if (l == r) {
        tree[rt].sum = b[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}
void update(int rt, int pos, ll val) {  //
    if (tree[rt].l == tree[rt].r) {
        tree[rt].sum += val;
        return;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if (pos <= mid)
        update(rt << 1, pos, val);
    else
        update(rt << 1 | 1, pos, val);
    pushup(rt);
}
ll query(int rt, int l, int r) {
    if (l <= tree[rt].l && r >= tree[rt].r)
        return tree[rt].sum;
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    ll sum = 0;
    if (l <= mid)
        sum += query(rt << 1, l, r);
    if (r > mid)
        sum += query(rt << 1 | 1, l, r);
    return sum;
}

signed main() {
    char op[5];
    ll x, y, z;
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &b[i]);
    }
    build(1, 1, n);
    scanf("%lld", &m);
    while (m--) {
        scanf("%s%lld%lld", op, &x, &y);
        if (op[0] == 'A') {
            update(1, x, y);
        } else {
            ll t = query(1, x, y);
            printf("%lld\n", t);
        }
    }
    return 0;
}

 

2.Acwing : internal gcd

gcd(x,y) = gcd(x,y-x)

gcd(x,y,z) = gcd(x,y-x,z-y)

数学归纳法证明多个变量也满足此规律

那么:对于某一段al到ar的gcd,即gcd(al, al+1, al+2 ... ... ar),就是在求gcd(al, al+1 - al, al +2 - al+1... ... ar - ar-1),

如果对于原来数组某一段+d1或者-d2,差分后a数组都会被减掉,那么我们可以维护差分序列的gcd,即gcd(al+1 - al, al +2 - al+1... ... ar - ar-1),在上面进行单点的+d1或者-d2,最后求出l位置的前缀和以及其他位置差分数组的gcd。

用线段树维护差分序列,x的值可以通过线段树求出差分的前缀和t = query_one(1, 1, x)。

那么x到y的gcd就是query(t, query_gcd(1, x+1, y))的值。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
// #define int long long
#define ll long long
using namespace std;
const int mxn = 5e5 + 5;
ll n,m;
struct Tree{
    int l,r;
    ll sum, gcd;
}tree[mxn * 4];
ll a[mxn], b[mxn];
ll gcd(ll x, ll y){
    return y == 0 ? x: gcd(y,x % y);// y == 0 ? y: gcd(y, x - y);
}
void pushup(int rt){
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
    tree[rt].gcd = gcd(tree[rt<<1].gcd, tree[rt<<1|1].gcd);
}
void build(int rt, int l, int r){
    tree[rt].l = l, tree[rt].r = r;
    if(l == r){
        tree[rt].sum = b[l]; tree[rt].gcd = b[l];
        return;
    }
    int mid = (l + r) >>1;
    build(rt<<1, l, mid);
    build(rt<<1 | 1, mid+1, r);
    pushup(rt);
}
void update(int rt, int pos, ll val){//
    if(tree[rt].l == tree[rt].r){
        tree[rt].sum += val, tree[rt].gcd += val;
        return;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(pos <= mid)
        update(rt<<1, pos, val);
    else
        update(rt<<1 | 1, pos, val);
    pushup(rt);
}
 ll query_one(int rt, int l, int r){
     if(l <= tree[rt].l && r >= tree[rt].r) return tree[rt].sum;
     int mid = (tree[rt].l + tree[rt].r)>>1;
     ll sum = 0;
     if(l <= mid)
         sum += query_one(rt<<1, l, r);
     if(r > mid)
         sum += query_one(rt<<1|1, l , r);
     return sum;
 }
 ll query_gcd(int rt, int l, int r){
     if(l <= tree[rt].l && r >= tree[rt].r) return tree[rt].gcd;
     int mid = (tree[rt].l + tree[rt].r)>>1;
     ll lg = 0 ,rg = 0;//0 and another's gcd is another
     if(l <= mid)
         lg = query_gcd(rt<<1, l, r);
     if(r > mid)
         rg = query_gcd(rt<<1|1, l, r);
     return gcd(lg,rg);//error gcd(l,r);
 }

signed main(){
    char op; ll x,y,z;
    scanf("%lld%lld",&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%lld",&a[i]);
        b[i] = a[i] - a[i-1];
    }
    build(1,1,n);
     while(m--){
         scanf(" %c%lld%lld",&op,&x,&y);
         if(op == 'C'){
             scanf("%lld",&z);
             update(1, x, z);
             if(y + 1 <= n)
                 update(1, y+1, -z);
         }else{
             ll t = query_one(1, 1, x);
             printf("%lld\n",abs(gcd(t, query_gcd(1, x+1, y))));
         }
     }
    return 0;
}

 

3.上帝造题的七分钟/花神游历各国

对于开根号,可以发现,10^6最多开6次就到1了,那么对于某一段区间如果最大值是1,说明无需修改,如果>1,那么暴力开根号。因此维护一个最大值,一个求和即可。

void change(int rt, int l, int r){
    if(tree[rt].mx == 1) return;//当>1时暴力修改,当==1时不修改直接跳过 
    if(tree[rt].l == tree[rt].r){
        tree[rt].sum = sqrt(tree[rt].sum);
        tree[rt].mx = sqrt(tree[rt].mx);
        return;
    }
    int mid = (tree[rt].l + tree[rt].r)>>1;
    if(l <= mid)
        change(rt<<1, l, r);//这个范围不能更改 
    if(r > mid)
        change(rt<<1|1, l, r);
    pushup(rt);
}
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
ll n,m,a[N];
//维护什么信息,
//区间最大值,区间和 
//区间合并信息  
struct Tree{
    ll sum, mx, l, r;
}tr[N*4];
void pushup(int rt){
    tr[rt].sum = tr[rt<<1].sum + tr[rt<<1|1].sum;
    tr[rt].mx = max(tr[rt].mx, tr[rt<<1|1].mx);
}
void build(int rt, int l, int r){
    tr[rt].l = l, tr[rt].r = r;
    if(l == r){
        tr[rt].sum = a[l];
        tr[rt].mx = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
    pushup(rt);
}
void update(int rt, int l, int r){//单点修改 
    if(tr[rt].mx == 1) return;
    if(tr[rt].l == tr[rt].r){
        tr[rt].sum = sqrt(tr[rt].sum);
        tr[rt].mx = sqrt(tr[rt].mx);
        return;
    }
    int mid = (tr[rt].l + tr[rt].r)>>1;
    if(l <= mid) update(rt<<1, l, r);
    if(r > mid) update(rt<<1|1, l, r);
    pushup(rt); 
}
ll query(int rt, int l, int r){
    if(l <= tr[rt].l && r >= tr[rt].r){
        return tr[rt].sum;
    }
    int mid = (tr[rt].l + tr[rt].r)>>1;
    ll ans = 0;
    if(l <= mid)
        ans += query(rt<<1, l, r);
    if(r > mid)
        ans += query(rt<<1|1, l, r); 
    return ans;
}
int op,l,r;
int main(){
    cin>>n;
    for(int i = 1; i <= n; i++) cin>>a[i];
    build(1,1,n);
    cin>>m;
    for(int i = 1; i <= m; i++){
        cin>>op>>l>>r;
        if(l > r) swap(l,r);
        if(op == 0){
            update(1,l,r);
        } 
        else{
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}

 

 

 也可以用以下方法:

```

//如果这个区间的标记是0或者是1,那么这一段就都不用再修改了
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
int a[100005];
int x,l,r;
struct P {
    int l,r;
    int sum;
    bool flag;
} tree[400050];
void pushup(int t) {
    tree[t].sum =tree[t*2].sum +tree[t*2+1].sum ;
    if(tree[t*2].flag and tree[t*2+1].flag )tree[t].flag=1;
    return;
}
void build(int t,int l,int r) {
    tree[t].l =l; tree[t].r =r;
    if(l==r) {
        tree[t].sum =a[l];
        if(a[l]==1 or (not a[l]))tree[t].flag=1;
        return;
    }
    int mid=(l+r)/2.0;
    build(t*2,l,mid);
    build(t*2+1,mid+1,r);
    pushup(t);
    return;
}
int qcheck(int t,int l,int r) {
    if(l<=tree[t].l and tree[t].r <=r) {
        return tree[t].sum ;
    }
    int mid=(tree[t].l +tree[t].r)/2.0;
    int ans=0;
    if(l<=mid)ans=qcheck(t*2,l,r);
    if(r>mid)ans+=qcheck(t*2+1,l,r);
    pushup(t);
    return ans;
}
void cnote(int t,int l,int r) {
    if(tree[t].flag )return;
    if(tree[t].l ==tree[t].r ) {
        tree[t].sum =(int)sqrt(tree[t].sum );
        if(tree[t].sum == 1 or not(tree[t].sum ))tree[t].flag=1;
        return;
    }
    int mid=(tree[t].l +tree[t].r )/2.0;
    if(l<=mid)cnote(t*2,l,r);
    if(r>mid) cnote(t*2+1,l,r);
    pushup(t);
    return;
}
signed main() {
    ios::sync_with_stdio(0);
    cin>>n;
    for(int i=1; i<=n; ++i) {
        cin>>a[i];
    }
    build(1,1,n);
    cin>>m;
    for(int i=1; i<=m; ++i) {
        cin>>x>>l>>r;
        if(l > r) swap(l,r);
        if(x==0) {
            cnote(1,l,r);
        }else{
            cout<<qcheck(1,l,r)<<endl;
        }
    }
    return 0;
}
/*
4
1 100 5 5
2
2 1 2
1 1 2

输入11
*/

```

4.区间修改,单点查询

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
#define int long long
#define MAXN 1000005
using namespace std;
int n, m;
LL a[MAXN];
struct Node {
    int l, r;
    LL sm, ad;
} tre[MAXN << 2];
inline void pushup(int rt) { tre[rt].sm = tre[rt << 1].sm + tre[rt << 1 | 1].sm; }
inline void pushdown(int rt) {
    if (tre[rt].ad) {
        int tad = tre[rt].ad;
        tre[rt << 1].ad += tad;
        tre[rt << 1 | 1].ad += tad;
        tre[rt << 1].sm +=
            tad * (tre[rt << 1].r - tre[rt << 1].l +
                   1);  //(2)下放标记的同时,将该区间的sm值更新,以便于下次查询可以有sm的正确返回值
        tre[rt << 1 | 1].sm += tad * (tre[rt << 1 | 1].r - tre[rt << 1 | 1].l + 1);
        tre[rt].ad = 0;
    }
}
inline void build(int rt, int L, int R) {
    tre[rt].l = L, tre[rt].r = R;
    if (L == R) {
        tre[rt].sm = a[L];
        return;
    }
    int mid = (L + R) >> 1;
    build(rt << 1, L, mid);
    build(rt << 1 | 1, mid + 1, R);
    pushup(rt);
}
inline void update(int rt, int L, int R, int v)  //区间修改
{
    if (L <= tre[rt].l && R >= tre[rt].r) {
        tre[rt].sm += (tre[rt].r - tre[rt].l + 1) * v;
        tre[rt].ad += v;
        return;
    }
    if (tre[rt].ad)
        pushdown(rt);  //(1)
    int mid = (tre[rt].l + tre[rt].r) >> 1;
    if (L <= mid)
        update(rt << 1, L, R, v);
    if (R > mid)
        update(rt << 1 | 1, L, R, v);
    pushup(rt);
}
inline LL query(int rt, int pos) {
    if (tre[rt].l == tre[rt].r) {
        return tre[rt].sm;
    }
    if (tre[rt].ad)
        pushdown(rt);
    int mid = (tre[rt].l + tre[rt].r) >> 1;
    if (pos <= mid)
        return query(rt << 1, pos);  //少+
    else
        return query(rt << 1 | 1, pos);
}
signed main() {
    scanf("%lld%lld", &n, &m);
    for (register int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    build(1, 1, n);
    //    for(int i=1;i<=9;i++)cout<<tre[i].sm<<" "<<tre[i].l<<" "<<tre[i].r<<endl;
    int q, x, y;
    LL k;
    int pos;
    for (register int i = 1; i <= m; i++) {
        scanf("%lld", &q);
        if (q == 2) {
            scanf("%lld", &pos);
            printf("%lld\n", query(1, pos));
        } else {
            scanf("%lld%lld%lld", &x, &y, &k);
            if (k == 0)
                continue;
            update(1, x, y, k);
        }
    }
}

 

5.区间修改,区间查询

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXN 1000005
#define LL long long
#define int long long
using namespace std;
int n, m;
LL a[MAXN];
struct Node {
    int l, r;
    LL sm, ad;
} tre[MAXN << 2];
void pushup(int rt) { tre[rt].sm = tre[rt << 1].sm + tre[rt << 1 | 1].sm; }
void pushdown(int rt) {
    if (tre[rt].ad) {
        int tad = tre[rt].ad;
        tre[rt << 1].ad += tad;
        tre[rt << 1 | 1].ad += tad;
        tre[rt << 1].sm +=
            tad * (tre[rt << 1].r - tre[rt << 1].l +
                   1);  //(2)下放标记的同时,将该区间的sm值更新,以便于下次查询可以有sm的正确返回值
        tre[rt << 1 | 1].sm += tad * (tre[rt << 1 | 1].r - tre[rt << 1 | 1].l + 1);
        tre[rt].ad = 0;
    }
}
void build(int rt, int L, int R) {
    tre[rt].l = L, tre[rt].r = R;
    if (L == R) {
        tre[rt].sm = a[L];
        return;
    }
    int mid = (L + R) >> 1;
    build(rt << 1, L, mid);
    build(rt << 1 | 1, mid + 1, R);
    pushup(rt);
}
void update(int rt, int L, int R, int v)  //区间修改
{
    if (L <= tre[rt].l && R >= tre[rt].r) {
        tre[rt].sm += (tre[rt].r - tre[rt].l + 1) * v;
        tre[rt].ad += v;
        return;
    }
    pushdown(rt);  //(1)
    int mid = (tre[rt].l + tre[rt].r) >> 1;
    if (L <= mid)
        update(rt << 1, L, R, v);
    if (R > mid)
        update(rt << 1 | 1, L, R, v);
    pushup(rt);
}
LL query(int rt, int L, int R) {
    if (L <= tre[rt].l && R >= tre[rt].r) {
        return tre[rt].sm;
    }
    pushdown(rt);
    int mid = (tre[rt].l + tre[rt].r) >> 1;
    LL ans = 0;
    if (L <= mid)
        ans += query(rt << 1, L, R);  //少+
    if (R > mid)
        ans += query(rt << 1 | 1, L, R);
    return ans;
}
signed main() {
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    build(1, 1, n);
    //    for(int i=1;i<=9;i++)cout<<tre[i].sm<<" "<<tre[i].l<<" "<<tre[i].r<<endl;
    int q, x, y;
    LL k;
    for (int i = 1; i <= m; i++) {
        scanf("%lld", &q);
        if (q == 2) {
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", query(1, x, y));
        } else {
            scanf("%lld%lld%lld", &x, &y, &k);
            update(1, x, y, k);
        }
    }
}

 

6线段树2(区间加乘,区间查询)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define mxn 100005
#define int long long
using namespace std;
int n, m, p, a[mxn], v, x, y, k;
struct Tree {
    int l, r, mul, ad, rt, sum, len;
} tree[mxn << 2];
void pushup(int rt) { tree[rt].sum = (tree[rt << 1].sum + tree[rt << 1 | 1].sum) % p; }
void pushdown(int rt) {
    int tad = tree[rt].ad;
    int tml = tree[rt].mul;
    tree[rt].ad = 0;
    tree[rt].mul = 1;
    tree[rt << 1].ad = (tree[rt << 1].ad * tml + tad) % p;          // p
    tree[rt << 1 | 1].ad = (tree[rt << 1 | 1].ad * tml + tad) % p;  // p
    tree[rt << 1].mul = (tree[rt << 1].mul * tml) % p;
    tree[rt << 1 | 1].mul = (tree[rt << 1 | 1].mul * tml) % p;
    tree[rt << 1].sum = (tree[rt << 1].sum * tml + tad * tree[rt << 1].len) % p;
    tree[rt << 1 | 1].sum = (tree[rt << 1 | 1].sum * tml + tad * tree[rt << 1 | 1].len) % p;
}  //((x * mul) + ad) * mul' + ad' = x * mul * mul' + ad * mul' + ad'
// sum: sigma((x * mul) + ad)
void build(int l, int r, int rt) {
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].mul = 1;
    tree[rt].ad = 0;
    tree[rt].len = r - l + 1;
    if (l == r) {
        tree[rt].sum = a[l] % p;
        return;
    }
    int mid = (r + l) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, (rt << 1) | 1);
    pushup(rt);
}
void update_ad(int l, int r, int rt, int ad) {  //((x * mul) + ad) + ad'
    if (l <= tree[rt].l && r >= tree[rt].r) {
        tree[rt].ad = (tree[rt].ad + ad) % p;
        tree[rt].sum = (tree[rt].sum + ad * tree[rt].len) % p;
        return;
    }
    if (l > tree[rt].r || r < tree[rt].l)
        return;
    pushdown(rt);
    update_ad(l, r, rt << 1, ad);
    update_ad(l, r, rt << 1 | 1, ad);
    pushup(rt);
}
int query(int l, int r, int rt) {
    // cout<<l<<" "<<r<<" "<<rt<<" "<<tree[rt].l<<" "<<tree[rt].r<<endl;
    if (l <= tree[rt].l && r >= tree[rt].r) {
        return tree[rt].sum;
    }
    if (r < tree[rt].l || l > tree[rt].r)
        return 0;
    pushdown(rt);
    int tmp = 0;
    tmp += query(l, r, rt << 1) % p;
    tmp += query(l, r, rt << 1 | 1) % p;
    return tmp % p;
}
//((x * mul) + add) * mul' = x * mul * mul' + add * mul'
void update_mul(int l, int r, int rt, int mul) {
    if (l <= tree[rt].l && r >= tree[rt].r) {
        tree[rt].mul = (tree[rt].mul * mul) % p;
        tree[rt].ad = (tree[rt].ad * mul) % p;
        tree[rt].sum = (tree[rt].sum * mul) % p;
        return;
    }
    if (r < tree[rt].l || l > tree[rt].r)
        return;
    pushdown(rt);
    update_mul(l, r, rt << 1, mul);
    update_mul(l, r, rt << 1 | 1, mul);
    pushup(rt);
}
signed main() {
    scanf("%lld%lld", &n, &p);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    build(1, n, 1);
    // for(int i = 1; i <= 2*n ; i++)
    //   cout<<i<<" "<<tree[i].sum<<endl;
    scanf("%lld", &m);
    for (int i = 1; i <= m; i++) {
        scanf("%lld", &v);
        if (v == 1) {  // mul process - ad = ad * mul , mul =  mul
            scanf("%lld%lld%lld", &x, &y, &k);
            update_mul(x, y, 1, k);
        } else if (v == 2) {  // add process - mul no change , ad + ad'
            scanf("%lld%lld%lld", &x, &y, &k);
            update_ad(x, y, 1, k);
            // for(int i = 1; i <= 2*n ; i++)
            //   cout<<i<<" "<<tree[i].sum<<endl;
        } else if (v == 3) {
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", query(x, y, 1));
        }
    }
    return 0;
}

 

小白逛公园

 

P5490 扫描线

1.如图所示,进入矩形线段树值+1,出了矩形线段树值-1。

2.由于数据比较大,所以需要离散化。但是离散化以后,一个点不能代表点,而代表相邻的两个位置。比如样例:

100 150 200 255

离散化以后是 1 2 3 4

但是修改操作是100 - 200的线段树+1,

此时对于离散化后的是1-2的线段树+1,这样实际加的是100-150,250-200.

如果不是这样的话,会丢失长度。比如修改1,2,再修改3,那么总的线段树长度是1-2加上3,3是一个点就为0,那么2-3之间的距离丢失。

对于懒标记,可以不加的原因是因为区间加减成对出现。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,b[1000005];
struct Tree{
    int l,r,val,len;
}tree[4000005];
struct C{
    int x,ya,yb,f;
    bool operator < (const C p)const{
        return x < p.x;
    }
}c[1000005];
void pushup(int rt){
    if(tree[rt].val)
        tree[rt].len = b[tree[rt].r+1] - b[tree[rt].l];
    else
        tree[rt].len = tree[rt<<1].len + tree[rt<<1|1].len;
}
void build(int rt, int l, int r){
    tree[rt].l = l; tree[rt].r = r;
    if(l == r){
        tree[rt].val = 0;//
        return;
    }
    int mid = (l + r) >> 1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
//    tree[rt].len = tree[rt<<1].len + tree[rt<<1|1].len;
}

void change(int rt, int l, int r, int val){//tree[1].len 
    if(l <= tree[rt].l && r >= tree[rt].r){
        tree[rt].val += val;
        pushup(rt);
        return ;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(l <= mid)
        change(rt<<1, l, r, val);
    if(r > mid)
        change(rt<<1|1, l, r, val);
    pushup(rt);
}
signed main(){
    scanf("%lld",&n); int cnt = 0, xa, ya, xb, yb;
    for(int i = 1; i <= n; i++){
        scanf("%lld%lld%lld%lld",&xa, &ya, &xb, &yb);
        b[++cnt] = ya; c[cnt].f = 1, c[cnt].x = xa, c[cnt].ya = ya, c[cnt].yb = yb;
        b[++cnt] = yb; c[cnt].f = -1, c[cnt].x = xb, c[cnt].ya = ya, c[cnt].yb = yb;
    }
    sort(c+1, c+cnt+1);
    sort(b+1, b+cnt+1);
    int m = unique(b+1, b+cnt+1) - (b+1);
     
    build(1,1,m-1);

    int x,y,area = 0;
    for(int i = 1; i <= cnt; i++){
        x = lower_bound(b+1, b+m+1, c[i].ya) - b;
        y = lower_bound(b+1, b+m+1, c[i].yb) - b - 1;    
        area += tree[1].len * (c[i].x - c[i-1].x);
//        cout<<tree[1].len<<endl;
        change(1, x, y, c[i].f);
    }
    cout<<area<<endl;
    return 0;
}

 

楼房重建:(经典线段树)

1.首先想到斜率作为数值

2.维护斜率上升,且最左边的斜率是一定要的

3.左边维护好了,右边维护好了,如果进行区间合并? 如果想拼接成功,左边不动,右边二分一下

4.二分没有办法直接写,可以用递归的方式,再写一个函数。

#include<bits/stdc++.h>
#define N 100005
using namespace std;
double a[N];
void Tree{
    int l,r,cnt;
    double mx;
}tr[N<<2];
int cal(int rt, double x){
    int res = 0;
    if(tr[rt].mx <= x) return 0;
    if(tr[rt].l == tr[rt].r) return tr[rt].mx > x;
    int mid = (tr[rt].l + tr[rt].r)>>1;
    if(a[mid] > x){
        res = (tr[rt].r - mid) + cal(rt<<1, x);
    }
    else{
        res = cal(rt<<1|1, x);
    }
    return res;
}
void pushup(int rt){
    int ans = cal(rt<<1|1, tr[rt<<1].mx);
    tr[rt].cnt = tr[rt<<1].cnt + ans; 
    tr[rt].mx = max(tr[rt].mx, tr[rt<<1|1].mx);
}
void build(int rt, int l, int r){
    tr[rt].l = l, tr[rt].r = r;
    if(l == r){
        tr[rt].mx = 0.0;
        tr[rt].cnt = 0; 
        return;
    }
    int mid = (l+r)>>1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
}
void update(int rt, int pos, double v){
    if(tr[rt].l == tr[rt].r){
        tr[rt].mx = v;
        tr[rt].cnt = 1;
        return;
    }
    int mid = (tr[rt].l + tr[rt].r)>>1;
    if(pos <= mid) update(rt<<1, pos, v);
    else update(rt<<1|1, pos, v);
    pushup(rt);
}
int main(){
    cin>>n>>m;
    build(1,1,n);,
    for(int i = 1; i<= m; i++){
        cin>>x>>y;
        update(1, x, y*1.0/x);
        cout<<tr[1].cnt<<endl;
    }
    return 0;
}

 

宝宝排序:sdfzoj1767

1.贪心思想,尽量让右端点小。

2.维护左端点宝宝最小值成上升序列,右端点尽量小,mn

3.维护左端点宝宝最大值成上升序列,右端点尽量小,mx

4.可以参考两个宝宝的情况,取讲授

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
const int inf = 1000000001;
int n, m, u, v;
struct Node {
    int g, d;
} a[N];
struct Tree {
    int l, r, mx, mn;
} tr[N << 2];
void pushup(int rt) {
    tr[rt].mx = tr[rt].mn = inf;  //如果下面的满足则会更改成不是inf
    int w = tr[rt << 1 | 1].l;
    //    cout<<"w: "<<w<<endl;
    if (tr[rt << 1].mx <= a[w].g)
        tr[rt].mx = min(tr[rt].mx, tr[rt << 1 | 1].mx);
    if (tr[rt << 1].mx <= a[w].d)
        tr[rt].mx = min(tr[rt].mx, tr[rt << 1 | 1].mn);
    if (tr[rt << 1].mn <= a[w].g)
        tr[rt].mn = min(tr[rt].mn, tr[rt << 1 | 1].mx);
    if (tr[rt << 1].mn <= a[w].d)
        tr[rt].mn = min(tr[rt].mn, tr[rt << 1 | 1].mn);
}
void build(int rt, int l, int r) {
    //    tr[rt]= (Tree){l,r,inf,inf};
    tr[rt].l = l, tr[rt].r = r;
    if (l == r) {
        tr[rt].mx = a[l].g;
        tr[rt].mn = a[l].d;
        return;
    }
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}
void update(int rt, int l, int r, int x) {
    if (l == r) {
        tr[rt].mx = a[x].g, tr[rt].mn = a[x].d;
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(rt << 1, l, mid, x);
    else
        update(rt << 1 | 1, mid + 1, r, x);
    pushup(rt);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].g >> a[i].d;
        if (a[i].d > a[i].g)
            swap(a[i].d, a[i].g);
    }
    build(1, 1, n);
    // cout<<tr[1].mn<<" "<<tr[1].mx<<endl;
    cin >> m;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v;
        swap(a[u], a[v]);
        update(1, 1, n, u);
        update(1, 1, n, v);
        if (tr[1].mx != inf || tr[1].mn != inf)
            puts("1");
        else
            puts("0");
    }
    return 0;
}
/*
2
1 4
3 5
out:3 5
*/

 

posted on 2020-08-23 18:58  Jeanny  阅读(201)  评论(0)    收藏  举报