[uoj228]基础数据结构练习题 解题报告

这题好厉害呀。。

看完题一看。。相邻两个数开根号的话差会由a-b变成ab,相当于除了一个a+b,这样的话很快差就要变成0了,傻逼题呀!这样只需搞一棵线段树,如果一个区间都是一个数了,就直接开根号,相当于打个覆盖标记,否则的话就递归下去;这样递归下去的条件是一个区间有相邻两个数差不为0,这样会使得原区间裂成 lg区间长度 个小区间,而对于一个差而言只会造成这种情况lglgn次;区间加的话就相当于是重置了两端的差,所以时间复杂度是O((n+m)lgnlglgn)
然后写完一交,70.
一看数据。。差为1…卧槽?!
原来当差为1的时候开完根号可能差还是为1,就是如果a是一个完全平方数,b=a-1,那么a=b+1。但是只有差为1才会出现这种情况,因为如果a=b+2的话,a-b最小的情况也是a=9,b=3,a-b=6了。

这个hack点有点强啊。。
于是我想,原来我是当一个区间所有数相同的时候就统一处理,那么就改一下,改成所有数差≤1时统一处理吧,记一下最大值、最小值、最大值出现次数。。然后就改呀改,终于ac了。

然后膜拜了一个大神的题解,原来差为1的时候只需要把它看成区间减操作就行了!我果然是傻逼。。。
代码:

#include
#include
using namespace std;
#include
#include
#include
const int N=1e5+5,M=1e5+5;
typedef long long LL;
int a[N];

char * cp=(char *)malloc(5000000);
void in(int &x){
    while(*cp<'0'||*cp>'9')++cp;
    for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');
}

char * os=(char *)malloc(2000000),* op=os;
void out(LL x)
{
    if(x)
    {
        out(x/10);
        *op++=x%10^'0';
    }
}

struct SS
{
    LL sum;

    LL delta;

    LL max,min;
    int maxcnt;
    LL cover0,cover1;
}segt[N<<2];
#define lson node*2,l,(l+r)/2
#define rson node*2+1,(l+r)/2+1,r
#define self node,l,r
void out(int node,int l,int r){
    printf("Segt(%d,[%d,%d])={sum=%I64d,delta=%I64d,max=%I64d,min=%I64d,maxcnt=%d,cover0=%I64d,cover1=%I64d}\n",node,l,r,segt[node].sum,segt[node].delta,segt[node].max,segt[node].min,segt[node].maxcnt,segt[node].cover0,segt[node].cover1);
}
void pushup(int node)
{
    segt[node].sum=segt[node<<1].sum+segt[node<<1|1].sum;
    segt[node].max=max(segt[node<<1].max,segt[node<<1|1].max);
    segt[node].min=min(segt[node<<1].min,segt[node<<1|1].min);

    segt[node].maxcnt=0;
    if(segt[node<<1].max==segt[node].max)segt[node].maxcnt+=segt[node<<1].maxcnt;
    if(segt[node<<1|1].max==segt[node].max)segt[node].maxcnt+=segt[node<<1|1].maxcnt;
}
void cover_paint(int node,int l,int r,LL cover0,LL cover1)
{
    //printf("cover_paint(%d,[%d,%d],%I64d,%I64d)\n",node,l,r,cover0,cover1);

    segt[node].delta=0;
    segt[node].sum=cover0*segt[node].maxcnt+(r-l+1-segt[node].maxcnt)*cover1;
    segt[node].max=segt[node].cover0=cover0,segt[node].min=segt[node].cover1=cover1;
    if(cover0==cover1)segt[node].maxcnt=r-l+1;
}
void delta_paint(int node,int l,int r,LL delta)
{
    segt[node].sum+=(r-l+1)*delta;
    segt[node].max+=delta,segt[node].min+=delta;
    if(segt[node].cover0)segt[node].cover0+=delta,segt[node].cover1+=delta;
    else segt[node].delta+=delta;
}
void pushdown(int node,int l,int r)
{
    if(segt[node].cover0)
    {
        LL lcover=segt[node<<1].max>=segt[node<<1|1].max?segt[node].cover0:segt[node].cover1,rcover=segt[node<<1|1].max>=segt[node<<1].max?segt[node].cover0:segt[node].cover1;
        cover_paint(lson,lcover,segt[node<<1].max==segt[node<<1].min?lcover:segt[node].cover1);
        cover_paint(rson,rcover,segt[node<<1|1].max==segt[node<<1|1].min?rcover:segt[node].cover1);
        segt[node].cover0=0;
    }
    else if(segt[node].delta)
    {
        delta_paint(lson,segt[node].delta),delta_paint(rson,segt[node].delta);
        segt[node].delta=0;
    }
}
void build(int node,int l,int r)
{
    if(l==r)segt[node]=(SS){a[l],0,a[l],a[l],1};
    else
    {
        build(lson),build(rson);
        pushup(node);
    }

    //out(self);
}
void add(int node,int l,int r,int L,int R,int x)
{
    if(L<=l&&r<=R)delta_paint(self,x);
    else
    {
        pushdown(self);
        if(L<=(l+r)/2)add(lson,L,R,x);
        if(R>(l+r)/2)add(rson,L,R,x);
        pushup(node);
    }

    //out(self);
}
void sqroot(int node,int l,int r,int L,int R)
{
    if(L<=l&&r<=R&&segt[node].max-segt[node].min<=1)cover_paint(self,(LL)sqrt(segt[node].max),(LL)sqrt(segt[node].min));
    else
    {
        pushdown(self);
        if(L<=(l+r)/2)sqroot(lson,L,R);
        if(R>(l+r)/2)sqroot(rson,L,R);
        pushup(node);
    }

    //out(self);
}
LL query(int node,int l,int r,int L,int R){
    //out(self);

    if(L<=l&&r<=R)return segt[node].sum;
    else
    {
        pushdown(self);
        LL ans=0;
        if(L<=(l+r)/2)ans+=query(lson,L,R);
        if(R>(l+r)/2)ans+=query(rson,L,R);
        return ans;
    }
}
int main(){
    freopen("uoj228.in","r",stdin);
    freopen("uoj228.out","w",stdout);
    fread(cp,1,5000000,stdin);
    int n,m;
    in(n),in(m);
    for(int i=1;i<=n;++i)in(a[i]);
    build(1,1,n);
    int opt,l,r,x;
    while(m--){
        //puts("----------");

        in(opt),in(l),in(r);
        switch(opt){
            case 1:
                in(x);
                add(1,1,n,l,r,x);
                break;
            case 2:
                sqroot(1,1,n,l,r);
                break;
            case 3:
                out(query(1,1,n,l,r));
                *op++='\n';
                break;
        }
    }
    fwrite(os,1,op-os,stdout);
}

总结:
①下取整和不下取整还是有区别的。。一定要考虑清楚这个问题。

你可能感兴趣的:(特殊数据,线段树)