20170121 机房『练习赛』

20170121 机房『练习赛』

我们最好把自己的生命看做前人生命的延续,是现在共同生命的一部分,同时也后人生命的开端。如此延续下去,科学就会一天比一天灿烂,社会就会一天比一天更美好。
—— 华罗庚

我热爱生活,我是一名快速成长的OIer

目录:

T1 setsum

#define PROGRAM_NAME "setsum"
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100000+10000;
template<class TE>inline void readin(TE &res) {
    char ch;
    int flag=1;
    while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;
    res=ch-48;
    while ((ch=getchar())>='0' && ch<='9')
        res=(res<<1)+(res<<3)+ch-48;
    res*=flag;
}
struct Node {
    int sum, flag;
    Node *ls, *rs;
    Node(){
        sum=0;
        ls=NULL;
        rs=NULL;
    }
    void pushdown(int lf, int rg) {
        if (flag){
            int mid=(lf+rg)>>1;
            ls->sum=(mid-lf+1)*flag;
            rs->sum=(rg-mid)*flag;
            ls->flag=flag;
            rs->flag=flag;
            flag=0;
        }
    }
}pool[2*MAXN+1000], *tail=pool, *root;
int N, aa[MAXN];

Node *build(int lf, int rg)
{
    Node *nd=++tail;
    if (lf==rg) {
        nd->sum=aa[lf];
    }else {
        int mid=(lf+rg)>>1;
        nd->ls=build(lf,mid);
        nd->rs=build(mid+1,rg);
        nd->sum=nd->ls->sum+nd->rs->sum;
    }
    //printf("build:%d %d %d\n",nd-pool,lf,rg);
    return nd;
}

void init()
{
    readin(N);
    for (int i=1; i<=N; i++) readin(aa[i]);
    root=build(1,N);
}

void modify(struct Node *nd, int lf, int rg, int L, int R, int val)
{
    if (L<=lf && rg<=R) {
        nd->sum=(rg-lf+1)*val;
        nd->flag=val;
    }else {
        int mid=(lf+rg)>>1;
        nd->pushdown(lf,rg);
        if (L<=mid) modify(nd->ls,lf,mid,L,R,val);
        if (R>mid) modify(nd->rs,mid+1,rg,L,R,val);
        nd->sum=nd->ls->sum+nd->rs->sum;
    }
    //printf("modify:%d %d %d\n",lf,rg,nd->sum);
}
int query(struct Node *nd, int lf ,int rg, int L, int R)
{
    //printf("query:%d %d %d\n",nd-pool,lf,rg);
    if (L<=lf && rg<=R) {
        return nd->sum;
    }else {
        int mid=(lf+rg)>>1, td=0;
        nd->pushdown(lf,rg);
        if (L<=mid) td+=query(nd->ls,lf,mid,L,R);
        if (R>mid) td+=query(nd->rs,mid+1,rg,L,R);
        return td;
    }
}

int Q, L, R, val;
char ss[100];
void solve()
{
    readin(Q);
    for (int i=1; i<=Q; i++)
    {
        scanf("%s",ss);
        if (ss[0]=='m') {
            readin(L);
            readin(R);
            readin(val);
            modify(root,1,N,L,R,val);
        } else {
            readin(L);
            readin(R);
            printf("%d\n",query(root,1,N,L,R));
        }
    }
}

int main()
{
    freopen(PROGRAM_NAME".in","r",stdin);
    freopen(PROGRAM_NAME".out","w",stdout);
    init();
    solve();
    return 0; 
}

第一题最开始时0分,线段树轻轻松松破百行。区间修改,区间求和。需注意的是,flag与sum都不可再用“+=”,因为是覆盖,覆盖便意味着是“=”,但是只改了sum而未改flag。0分!将flag改了以后轻松AC,确实理解不够深入。(P.S.:上课不听非非讲,受害很深重)
时间复杂度: O(nlogn+Qlogn)

T2 subtree

#define PROGRAM_NAME "subtree"
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100100;
const int MAXM = MAXN*2;
template<class TE>inline void readin(TE &res) {
    char ch;
    int flag=1;
    while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;
    res=ch-48;
    while ((ch=getchar())>='0' && ch<='9')
        res=(res<<1)+(res<<3)+ch-48;
    res*=flag;
}
struct Node {
    long long sum;
    Node *ls, *rs;
    Node(){
        sum=0;
        ls=NULL;
        rs=NULL;
    }
}pool[2*MAXN+1000], *tail=pool, *root;
int N;
long long aa[MAXN];

struct Edge
{
    int v, next;
}t[MAXM+1000];
int num=0, head[MAXN];
inline void insert(int u, int v)
{
    t[++num].v=v;
    t[num].next=head[u];
    head[u]=num;
}
int in[MAXN], out[MAXN], order[MAXN], INDEX=0;
void dfs(int u, int f)
{
    in[u]=++INDEX;
    order[INDEX]=u;
    //printf("DFS:%d %d %d\n",u,f,in[u]);
    for (int i=head[u]; i!=0; i=t[i].next) if (t[i].v!=f) dfs(t[i].v,u);
    out[u]=INDEX;
}

Node *build(int lf, int rg)
{
    Node *nd=++tail;
    if (lf==rg) {
        nd->sum=aa[order[lf]];
        //printf("BUILD:%d %d %d\n",lf,in[lf],aa[in[lf]]);
    }else {
        int mid=(lf+rg)>>1;
        nd->ls=build(lf,mid);
        nd->rs=build(mid+1,rg);
        nd->sum=nd->ls->sum+nd->rs->sum;
    }
    //printf("build:%d %d %d\n",lf,rg,nd->sum);
    return nd;
}

int u, v;
void init()
{
    memset(head,0,sizeof(head));
    readin(N);
    for (int i=1; i<=N; i++) readin(aa[i]);
    for (int i=1; i<=N-1; i++)
    {
        readin(u);
        readin(v);
        insert(u,v);
        insert(v,u);
    }
    dfs(1,0);
    //for (int i=1; i<=N; i++) printf("%d ",in[i]);printf("\n");
    //for (int i=1; i<=N; i++) printf("%d ",out[i]);printf("\n");
    root=build(1,N);
}

void modify(struct Node *nd, int lf, int rg, int pos, int val)
{
    if (lf==rg) {
        nd->sum+=val;
        //printf("modify:%d %d %d %d\n",lf,rg,val,nd->sum);
    }else {
        int mid=(lf+rg)>>1;
        if (pos<=mid) modify(nd->ls,lf,mid,pos,val);
        else modify(nd->rs,mid+1,rg,pos,val);
        nd->sum=nd->ls->sum+nd->rs->sum;
    }
    //printf("modify:%d %d %d\n",lf,rg,nd->sum);
}
long long query(struct Node *nd, int lf ,int rg, int L, int R)
{
    //printf("query:%d %d %d\n",nd-pool,lf,rg);
    if (L<=lf && rg<=R) {
        return nd->sum;
    }else {
        int mid=(lf+rg)>>1;
        long long td=0;
        if (L<=mid) td+=query(nd->ls,lf,mid,L,R);
        if (R>mid) td+=query(nd->rs,mid+1,rg,L,R);
        return td;
    }
}

int Q, pos, val, L, R;
char ss[100];
void solve()
{
    readin(Q);
    for (int i=1; i<=Q; i++)
    {
        scanf("%s",ss);
        if (ss[0]=='m') {
            readin(pos);
            readin(val);
            modify(root,1,N,in[pos],val);
        } else {
            readin(pos);
            cout << query(root,1,N,in[pos],out[pos]) << endl;
        }
    }
}

int main()
{
    freopen(PROGRAM_NAME".in","r",stdin);
    freopen(PROGRAM_NAME".out","w",stdout);
    init();
    solve();
    return 0; 
}

第二题开始只有30分,树套线段树。先前向星,再DFS求in和out,根据in的值确定节点位置,建树时节点加点权,修改单点,查询in与out构成的区间。单点修改点权,子树求和。需深入理解DFS序。(就是MAXN开的不够,血的教训!
时间复杂度: O(nlogn+Qlogn)

T3 matgcd

#define PROGRAM_NAME "matgcd"
#include <cstdio>
#include <ctime>
const int MAXN = 500+10;
const int MAXM = MAXN;
const int LOGM = 9+1;
const int MAXQ = 100000;
template<class TE>inline void readin(TE &res) {
    char ch;int flag=1;
    while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;res=ch-48;
    while ((ch=getchar())>='0' && ch<='9') res=(res<<1)+(res<<3)+ch-48;
    res*=flag;
}
inline int gcd(int x, int y){while (1){if (y==0) return x;int b=x;x=y;y=b%y;}}
const int pow2[]={1,2,4,8,16,32,64,128,256,512};
inline int log2(int n){for (int i=0; i<=9; i++) if (pow2[i+1]>n) return i;}
int N, M, Q, a, b, c, d, log2N, log2M;
int f[MAXN][10][MAXM][10];

void init()
{
    readin(N);
    readin(M);
    readin(Q);
    for (int i=1; i<=N; i++)
        for (int j=1; j<=M; j++)
            readin(f[i][0][j][0]);
    log2N=log2(N);
    log2M=log2(M);
    for (int j=1; j<=log2M; j++)
        for (int x=1; x<=N; x++)
            for (int y=1; y<=M-pow2[j]+1; y++)
            {
                a=f[x][0][y][j-1];
                b=f[x][0][y+pow2[j-1]][j-1];
                f[x][0][y][j]=gcd(a,b);
            }
    for (int i=1; i<=log2N; i++)
        for (int x=1; x<=N-pow2[i]+1; x++)
            for (int y=1; y<=M; y++)
            {
                a=f[x][i-1][y][0];
                b=f[x+pow2[i-1]][i-1][y][0];
                f[x][i][y][0]=gcd(a,b);
            }
    for (int i=1; i<=log2N; i++)
        for (int j=1; j<=log2M; j++)
            for (int x=1; x<=N-pow2[i]+1; x++)
                for (int y=1; y<=M-pow2[j]+1; y++)
                {
                    a=f[x][i-1][y][j-1];
                    b=f[x+pow2[i-1]][i-1][y][j-1];
                    c=f[x][i-1][y+pow2[j-1]][j-1];
                    d=f[x+pow2[i-1]][i-1][y+pow2[j-1]][j-1];
                    f[x][i][y][j]=gcd(gcd(gcd(a,b),c),d);
                }
}

int q, x1, x2, y1, y2;
char ss[100];
void solve()
{
    for (int i=1; i<=Q; i++)
    {
        scanf("%s",ss);
        readin(x1);
        readin(y1);
        readin(x2);
        readin(y2);
        log2N=log2(x2-x1+1);
        log2M=log2(y2-y1+1);
        a=f[x1][log2N][y1][log2M];
        b=f[x2-pow2[log2N]+1][log2N][y1][log2M];
        c=f[x1][log2N][y2-pow2[log2M]+1][log2M];
        d=f[x2-pow2[log2N]+1][log2N][y2-pow2[log2M]+1][log2M];
        printf("%d\n",gcd(gcd(gcd(a,b),c),d));
    }
}   

int main()
{
    freopen(PROGRAM_NAME".in","r",stdin);
    freopen(PROGRAM_NAME".out","w",stdout);
    init();
    solve();
    return 0; 
}

第三题开始仅30分,ST表。之前仅用3维,时间复杂度很大,为 Onlog2n+nQ 。当Q达到足够大小时,准超时。而开成四维以后,虽预处理较烦,但能轻松应付Q。
时间复杂度: O((nlogn)2+Q)

经验与教训

这一次第一回仅60分,而第二回便升至240分,第三回终于修成正果(300-240=60爆数组,T2只开了100000而无“+…”)。在较复杂的数据结构中,任意一个小错误都能产生致命的伤害(例如左右子树搞混,未返回值,修改方法不对。。。),故很有必要建模版。叶余非提前交卷210,再改便又AK。叶余非很强,可以好好仰望他,好好请教他。

附录1: 大神与非大神的blog

WebsitesBelonging toP.S.
idy002 - 丁尧尧cnblogs高新的荣耀
lflame - 杨雅儒lofterOMG
yjq_naive - 杨景钦lofter国家集训队选手
阿波罗2003 - yyfcnblogs萌萌的小东西
mcfx - wsq自建必成大器
hzwer - 黄学长自建无需多言
董的博客自建入门教程必读
林荫高16级信竞公共博客CSDN强!
deadshotz - 程szcnblogs就是个高二的
lemonoil - lmyCSDN有待追赶
lemonoil - lmycnblogs小号
Doggu - gykCSDN呵呵
Doggu - gykcnblogs精美小号
maverickfw - wyyCSDNFAT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值