1. 程式人生 > >18寒假第二測

18寒假第二測

read mat bsp class src 9.png pushd ++ 16px

技術分享圖片

技術分享圖片

技術分享圖片

第一題:二維樹狀數組,bit[x][y]表示從(1,1)到(x,y)的和,二維的坐標從一維的推過來,正確性可以用一個遞增和一個遞減的序列單調性證明,至於構圖就當黑箱吧

#include <cstdio>

int n, m, q;

struct Case1 {
    int bit[100010];
    void modify( int p, int d ) {
        for( int i = p; i <= m; i += i & -i )
            bit[i] += d;
    }
    int query( int
r ) { int rt = 0; for( int i = r; i; i -= i & -i ) rt += bit[i]; return rt; } int query( int l, int r ) { return query(r) - query(l-1); } void solve() { while (q--) { char ss[100]; scanf( "%s", ss );
if( ss[0] == m ) { int x, y, d; scanf( "%d%d%d", &x, &y, &d ); modify( y, d ); } else { int x1, y1, x2, y2; scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 ); printf( "%d\n"
, query(y1,y2) ); } } } }case1;//一維 struct Case2 { int bit[1100][1100]; void modify( int x, int y, int d ) { for( int i = x; i <= n; i += i & -i ) for( int j = y; j <= m; j += j & -j ) bit[i][j] += d; } int query( int x, int y ) { int rt = 0; for( int i = x; i; i -= i & -i ) for( int j = y; j; j -= j & -j ) rt += bit[i][j]; return rt; } int query( int x1, int y1, int x2, int y2 ) { return query(x2,y2) - query(x1-1,y2) - query(x2,y1-1) + query(x1-1,y1-1); } void solve() { while(q--) { char ss[100]; scanf( "%s", ss ); if( ss[0] == m ) { int x, y, d; scanf( "%d%d%d", &x, &y, &d ); modify( x, y, d ); } else { int x1, y1, x2, y2; scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 ); printf( "%d\n", query(x1,y1,x2,y2) ); } } } }case2;//二維 int main() { freopen ( "matsum.in", "r", stdin ) ; freopen ( "matsum.out", "w", stdout ) ; scanf( "%d%d%d", &n, &m, &q ); if( n == 1 ) case1.solve(); else case2.solve(); }

第二題:裸的線段樹模板,註意把值傳上去和放下去的地方,寫掛了很多次。。。

#include<bits/stdc++.h>
using namespace std;

const int oo = 0x3f3f3f3f;

#define MAX_N 100005
long long sum ;
int mn, mx, a[MAX_N];
int n, m;
struct SegTree{
    struct node{
        long long sum;
        int vmin,vmax,lazy;
    };
    node Tree[MAX_N << 2];
    
    #define ls l, m, v << 1
    #define rs m+1, r, v << 1 | 1
    void push_up(int v){
        Tree[v].sum = Tree[v << 1].sum + Tree[v << 1 | 1].sum;
        Tree[v].vmin = min(Tree[v << 1].vmin, Tree[v << 1 | 1].vmin);
        Tree[v].vmax = max(Tree[v << 1].vmax, Tree[v << 1 | 1].vmax);    
    }
    void push_down(int l, int r, int v){
        int m = (l + r) >> 1;
        
        Tree[v << 1].sum += 1LL * Tree[v].lazy * (m - l +1);
        Tree[v << 1].vmin += Tree[v].lazy;
        Tree[v << 1].vmax += Tree[v].lazy;
        Tree[v << 1].lazy += Tree[v].lazy;
        
        Tree[v << 1 | 1].sum += 1LL * Tree[v].lazy * (r - m);
        Tree[v << 1 | 1].vmin += Tree[v].lazy;
        Tree[v << 1 | 1].vmax += Tree[v].lazy;
        Tree[v << 1 | 1].lazy += Tree[v].lazy;
        
        Tree[v].lazy = 0;
    }
    void build(int l = 1, int r = n, int v = 1){
        Tree[v].sum = Tree[v].vmin = Tree[v].vmax = Tree[v].lazy = 0;
        
        if(l ==r){
            Tree[v].sum = 1LL * a[l];
            Tree[v].vmin = Tree[v].vmax = a[l];
        }
        else {
            int  m = (l +r) >> 1;
            build(ls);
            build(rs);            
            push_up(v);
        }
    }
    
    void modify(int x,int L,int R,int l = 1, int r = n, int v = 1){
        if(l >= L && r <= R){// += x WA了8次,每次都用的lazy... 
            Tree[v].lazy += x;
            Tree[v].sum += 1LL * x * (r - l + 1);
            Tree[v].vmin += x;
            Tree[v].vmax += x;            
        }
        else {
            if(Tree[v].lazy)push_down(l,r,v);
            int m = (l + r) / 2;
            if(L <= m)modify(x,L,R,ls);
            if(R > m)modify(x,L,R,rs);
            push_up(v);            
        }    
    }
    
    node query(int L,int R,int l = 1, int r = n,int v = 1){
        if(l >= L && r <= R)
            return Tree[v];
        else {
            if(Tree[v].lazy) push_down(l,r,v);
            int m = (l + r) / 2;
            node ans;
            ans.vmin = oo, ans.vmax = -oo, ans.sum = 0;//init
            if(L <= m){
                node nw = query(L,R,ls);
                ans.vmin = min(ans.vmin, nw.vmin);
                ans.vmax = max(ans.vmax, nw.vmax);
                ans.sum += nw.sum;
            }
            if(R > m){
                node nw = query(L,R,rs);
                ans.vmin = min(ans.vmin, nw.vmin);
                ans.vmax = max(ans.vmax, nw.vmax);
                ans.sum += nw.sum;
            }
            return ans;
        }
    }
};

SegTree Tr;
int main(){
    freopen("segsum.in","r",stdin);
    freopen("segsum.out","w",stdout);
    cin>>n>>m;
    for(int i = 1; i <= n; i++)
        scanf("%d", a + i);
    Tr.build();
    for(int i = 1; i <= m; i++){
        string opt;
        cin>>opt;
        if(opt[0] == q){
            int l, r;
            scanf("%d%d",&l,&r);
            SegTree::node nw;
            nw = Tr.query(l,r);
            cout<<nw.vmin<<" "<<nw.vmax<<" "<<nw.sum<<endl;
        }
        else{
            int l, r, x;
            scanf("%d%d%d",&l,&r,&x);
            Tr.    modify(x,l,r);
        }
    }
}

線段樹找了好幾個板子,還是郭大俠的最好用,寫起來也簡單,但還是WA了很多次

註意:modify,query,build時要push_down, query時要push_up

modify是增加的val,不是lazy;

要記住更新m的值,ans給初值

不過指針跑的真的快

#include <bits/stdc++.h>

using namespace std;
#define maxn 100005
#define ll long long
int a[maxn],n,m,s;
void read(int &x){
    int f=1;x=0;char s=getchar();
    while(s<0||s>9){if(s==-)f=-1;s=getchar();}
    while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
    x*=f;
}

struct Info{
    ll sum;
    int vmin,vmax;
    Info(){}
    Info(ll sum,int vimn,int vmax):sum(sum),vmin(vimn),vmax(vmax){}
};
Info Merge(const Info &ls,const Info &rs){
    return Info((ls.sum + rs.sum), min(ls.vmin, rs.vmin), max(ls.vmax, rs.vmax) );
}
struct Node{
    Info info;
    int delta;
    Node *ls, *rs;

    void pushdown(int l,int r){
        if(!delta)return ;//!
        int m = (l + r) >> 1;
        ls->info.sum += 1LL * (m - l +1) * delta;
        ls->info.vmin += delta;
        ls->info.vmax += delta;
        ls->delta += delta;
        rs->info.sum += 1LL *(r - m) * delta;
        rs->info.vmin += delta;
        rs->info.vmax += delta;
        rs->delta += delta;

        delta = 0;
    }
    void update(){//!
        info = Merge(ls->info, rs->info);
    }
}pool[maxn * 3],*tail = pool, *root;

Node * build(int l = 1,int r = n){
    Node *nd = ++tail;
    if(l == r){
        nd->info = Info(a[l],a[l],a[l]); nd->delta = 0;
    
    }
    else {
        int m = (l + r) >> 1;
        nd->ls = build(l, m);
        nd->rs = build(m + 1, r);
        nd->delta = 0;
        nd->update();
    }
    return nd;
}
#define Ls nd->ls, l, m
#define Rs nd->rs, m+1, r
void modify(int delta, int L, int R, Node *nd, int l = 1, int r = n){
    if(l >= L && r <= R){
        nd->info.sum += 1LL * delta * (r - l + 1);
        nd->info.vmin += delta;
        nd->info.vmax += delta;
        nd->delta += delta;
    }
    else {
        nd->pushdown(l, r);
        int m = (l + r) >> 1;
        if(L <= m)modify(delta, L, R, Ls);
        if(R > m)modify(delta, L, R, Rs);
        nd->update();
    }
}

Info query(int L, int R, Node *nd, int l = 1, int r = n ){
    if(l >= L && r <= R)
      return nd->info;
    else {
        nd->pushdown(l, r);
        int m = (l + r) >> 1;
        if(R <= m)return query(L, R, Ls);
        else if(L > m)return query(L, R, Rs);
        else return Merge( query( L, R, Ls ),query( L, R, Rs ) );
    }
}
int main(){
    freopen("segsum.in","r",stdin);
    freopen("segsum.out","w",stdout);
    read(n), read(m);
    for(int i = 1; i <= n; i++)
        read(a[i]);
    root = build();
    for(int i = 1; i <= m; i++){
        string opt;
        cin>>opt;
        if(opt[0] == q){
            int l, r;
            read(l),read(r);
            Info nw = query(l,r,root);
            cout<<nw.vmin<<" "<<nw.vmax<<" "<<nw.sum<<endl;
        }
        else{
            int l, r, x;
            read(l), read(r), read(x);
            modify(x,l,r,root);
        }
    }
}

第三題:利用 gcd 可以取並集的特點,二維st表,將一個矩形分成四部分,求並起來的gcd,

求log是要開到maxn,不是n啊,這個錯看了三天,最後還是余力大佬幫忙看出來的

#include<iostream>
#include<cstdio>
using namespace std;
#define RG register//卡常
#define maxn 508
#define P 10
int lo[maxn],d[maxn][maxn][P + 1][P + 1];
int n, m, q;
int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a%b) ;
}
void read(int &x){
    int f=1;x=0;char s=getchar();
    while(s<0||s>9){if(s==-)f=-1;s=getchar();
    }
    while(s<=9&&s>=0){ x=x*10+s-0;s=getchar();
    }
    x*=f;
}


void init() {
    for( RG int pi = 0; pi <= P; pi++ )
        for( RG int pj = 0; pj <= P; pj++ ) {
            if( pi == 0 && pj == 0 ) continue;
            for( RG int i = 1; i + (1<<pi) - 1 <= n; i++ )
                for( RG int j = 1; j + (1<<pj) - 1 <= m; j++ ) {
                    if( pi == 0 ) {
                        d[i][j][pi][pj] = gcd( d[i][j][pi][pj-1], d[i][j + (1<<(pj-1))][pi][pj-1] );
                    } else {
                        d[i][j][pi][pj] = gcd( d[i][j][pi-1][pj], d[i + (1<<(pi-1))][j][pi-1][pj] );
                    }
                }
        }
}

int query(int x1,int yy,int x2,int y2){
    int pi = lo[x2 - x1 + 1], pj = lo[y2 - yy + 1];
    int ans1 = gcd(d[x1][yy][pi][pj], d[x2 - (1 << pi) + 1][yy][pi][pj]);
    int ans2 = gcd(d[x1][y2 - (1 << pj) + 1][pi][pj], d[x2 - (1 << pi) + 1][y2 - (1 << pj) + 1][pi][pj]);
    return gcd(ans1, ans2);

}

int main(){
    freopen("matgcd.in","r",stdin);
    freopen("matgcd.out","w",stdout);
    read(n),read(m),read(q);

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        read(d[i][j][0][0]);
    lo[0] = -1;
    for(int i = 1; i < maxn; i++)
        lo[i] = lo[i / 2] + 1;
    init();
    for(int i = 1; i <= q; i++){
        string opt;
        cin>>opt;
        int x1,yy,x2,y2;
        read(x1),read(yy),read(x2),read(y2);
        printf("%d\n",query(x1,yy,x2,y2));
    }

}

18寒假第二測