smoj2011(神奇的线段树)

来源:互联网 发布:梦幻手游宝宝评分算法 编辑:程序博客网 时间:2024/06/07 05:51

这题依然是比赛是碰到的,当时以为自己会做,最后10分钟才知道要打暴力,结果暴力打错了(传说暴力有70)
后来问了很多大犇,用了一个上午才想清楚了。(也许我对线段树一无所知)

这里写图片描述
这里写图片描述

大概就是棵线段树
经过小小的计算,猜测出题人的阴谋,这题常数是10(实测100常数比暴力低分)。

对于线段树的每个结点,我们用s[10]表示该区间0~9分别的权值和。我们只要正确地维护这个信息,就可用10的常数获得答案。

本题的修改操作是把区间的s[y]+=s[x],s[x]清零,因为这题是线段树,所以一定懒惰,就设lz[x]=y,表示该区间的s[x]应加给s[y]。

然后考虑下放标记,我们用(父亲没标记)等价于(儿子信息正确)的方法。(即该区间有无标记与该区间信息正确性无关)

儿子的s就根据父亲的lz数组来维护,lz大概是这样维护的

lz[x][i]=lz[fa[x]][lz[x]][i]

这样大概就是对的了。

。。完了,我现在觉得这个做法就是错的,这个信息根本维护不了,就是想不明白这个lz能重叠但又有先后顺序的情况
2017.9.19
17:18

#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))typedef long long LL;const int N=100100;void read(int &hy){    char cc=getchar();    hy=0;    while(cc<'0'||cc>'9')    cc=getchar();    while(cc>='0'&&cc<='9')    {        hy=(hy<<3)+(hy<<1)+cc-'0';        cc=getchar();    }}int b[N];int n,q,lz[4*N][10],vis[10];LL ten[15],a[N][10],s[4*N][10],by[10];void up(int ro){    for(int i=0;i<=9;i++)    s[ro][i]=s[ro*2][i]+s[ro*2+1][i];}void down(int ro,int l,int r){    if(l==r)    return;    int L=ro<<1,R=(ro<<1)|1;    for(int i=0;i<=9;i++)    vis[i]=lz[ro][lz[L][i]],by[i]=s[L][i];    for(int i=0;i<=9;i++)    by[lz[ro][i]]+=s[L][i],by[i]-=s[L][i];    for(int i=0;i<=9;i++)    lz[L][i]=vis[i],s[L][i]=by[i];    for(int i=0;i<=9;i++)    vis[i]=lz[ro][lz[R][i]],by[i]=s[R][i];    for(int i=0;i<=9;i++)    by[lz[ro][i]]+=s[R][i],by[i]-=s[R][i];    for(int i=0;i<=9;i++)    lz[R][i]=vis[i],s[R][i]=by[i];    for(int i=0;i<=9;i++)    lz[ro][i]=i;}LL get(int ro){    LL res=0ll;    for(LL i=1;i<=9;i++)    res+=s[ro][i]*i;    return res;}void build(int ro,int l,int r){    for(int i=0;i<=9;i++)    lz[ro][i]=i;    if(l==r)    {        for(int i=0;i<=9;i++)        s[ro][i]=a[l][i];        return;    }    int mid=(l+r)/2;    build(ro*2,l,mid);    build(ro*2+1,mid+1,r);    up(ro);}void update(int ro,int l,int r,int zuo,int you,int x,int y){    down(ro,l,r);    if(l>=zuo&&r<=you)    {        s[ro][y]+=s[ro][x];        s[ro][x]=0;        lz[ro][x]=y;        return;    }    int mid=(l+r)>>1;    if(zuo<=mid)    update(ro*2,l,mid,zuo,you,x,y);    if(you>mid)     update(ro*2+1,mid+1,r,zuo,you,x,y);    up(ro);}LL query(int ro,int l,int r,int zuo,int you){    down(ro,l,r);    if(l>you||r<zuo)    return 0ll;    if(l>=zuo&&r<=you)    return get(ro);    int mid=(l+r)>>1;    return query(ro*2,l,mid,zuo,you)+query(ro*2+1,mid+1,r,zuo,you);}int main(){    cin>>n>>q;    ten[0]=1ll;    for(int i=1;i<=11;i++)    ten[i]=ten[i-1]*10ll;    for(int i=1;i<=n;i++)    {        read(b[i]);        int tu=0;        int bb=b[i];        while(b[i])        {            a[i][b[i]%10]+=ten[tu];            tu++;            b[i]/=10;        }    }    build(1,1,n);    while(q--)    {        int ops,l,r,x,y;        read(ops);        read(l);        read(r);        if(ops==2)        printf("%lld\n",query(1,1,n,l,r));        else        {            read(x);            read(y);            if(x^y)            update(1,1,n,l,r,x,y);        }    }    return 0;}
原创粉丝点击