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));
    }

}

原文地址:https://www.cnblogs.com/EdSheeran/p/8423591.html

时间: 2024-07-30 20:09:14

18寒假第二测的相关文章

18寒假13测

题目名称 buy slide divide 输入 buy.in slide.in divide.in 输出 buy.out slide.out divide.out 每个测试点时限 1秒 1秒 1秒 内存限制 256MB 256MB 256MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 buy description: 地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最

18寒假12测

Day1 题目名称 party array treasure 输入 party.in array.in treasure.in 输出 party.out array.out treasure.out 每个测试点时限 1秒 1秒 1秒 内存限制 64MB 64MB 64MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 party 题目描述: 在M公司里,每个人只有一个直属上司(除了boss).这个公司举办派对,每个人可以给派

18寒假第一测

猪猪的想法输入文件:thought.in输出文件:thought.out时间限制:1 second空间限制:128 MB题目描述狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一个很有趣的事情--喜欢是可以传递的,例如猪猪喜欢猪猪,猪猪喜欢猪猪,那么可以说猪猪喜欢猪猪.有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险.现在给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出N

2015 年 JXNU_ACS 算法组寒假第二次周赛

2015 年 JXNU_ACS 算法组寒假第二次周赛 比赛链接:http://acm.hdu.edu.cn/diy/contest_show.php?cid=26246 Start Time : 2015-02-01 13:00:00 End Time : 2015-02-01 17:30:00 终榜:http://acm.hdu.edu.cn/diy/contest_ranklist.php?cid=26246&page=1 这次比赛考查的知识都很基础,甚至还有几道就是C语言基础(比如1006

开学第二测

开学第二测(好像是qbxt zhx出的题) P69 题目名称 希望 残  党 名称    kami na wosa 输入  kami.in   na.in wosa.in 输出  kami.out na.out  wosa.out 每个测试点时限 1 秒 1 秒 1 秒 内存限制 512MB 512MB 512MB 测试点数目  10 10 10 每个测试点分值  10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统  注意 事项(请务必仔细阅读):   T1 希望[题目描述]

寒假第二周 1.18 --- 1.24

1.18 cf 581c 581C - Developing Skills 重新自己写了一遍,注意都是0 的时候 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 1e5+5; 9 int n,k; 10 11

18寒假第三测

第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离 #include<bits/stdc++.h> using namespace std; const int maxn = 100015, P = 20; int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn]; void dfs(int u,int from){ //

18寒假第六测

第一题:乘法修改的线段树 一定不能将change,modify分类讨论定两个标记,会有顺序影响 lazy标记一定要long long,又忘了... 代码和上一次差不多 第二题:离散暴力,也可以扫描线 离散时要将格子映射成点,不然会出现以下情况: 算横着的小矩形宽就是2,算黄色面积宽还是2,因为没有2让3去减 如果映射成点,就像这样,,放图比较好理解,就像扫描线,一个叶子节点存的是一个左闭右开的区间 也可以离散+扫描线,但还没写出来 #include <bits/stdc++.h> using

18寒假第五测

第一题 线段树 树状数组存差b[i] = a[i]-a[i-1],反正是单点查询,我为什么没想到...很傻的用线段树 #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long int n, m, a[maxn]; struct SegmentTree{ struct node{ ll sum; int lazy; }; node Tree[maxn << 2]; #de