18寒假第二测

Posted edsheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18寒假第二测相关的知识,希望对你有一定的参考价值。

技术分享图片

技术分享图片

 

技术分享图片

 

第一题:二维树状数组,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寒假第二测的主要内容,如果未能解决你的问题,请参考以下文章

开学第二测

暑假第二测

9.5ZR提高组十连测第二测

BZOJ NOI十连测 第二测 T2

5.31联合第二测

18寒假第六测