bzoj3091

来源:互联网 发布:金妍儿 知乎 编辑:程序博客网 时间:2024/06/11 11:31

这道题加深了对lct的理解,先贴错误的代码,感觉错误的代码也很珍贵! 舍不得 Ctrl+A+Backspace。

本题维护的值的讲解的链接:http://blog.csdn.net/popoqqq/article/details/40823659

怎么求1^2+2^2+3^2……+n^2?

想像一个有圆圈构成的正三角形, 
第一行1个圈,圈内的数字为1 
第二行2个圈,圈内的数字都为2, 
以此类推 
第n行n个圈,圈内的数字都为n, 
我们要求的平方和,就转化为了求这个三角形所有圈内数字的和。设这个数为r 
下面将这个三角形顺时针旋转60度,得到第二个三角形 
再将第二个三角形顺时针旋转60度,得到第三个三角形 
然后,将这三个三角形对应的圆圈内的数字相加, 
我们神奇的发现所有圈内的数字都变成了2n+1 
而总共有几个圈呢,这是一个简单的等差数列求和 
1+2+……+n=n(n+1)/2 
于是3r=[n(n+1)/2]*(2n+1) 
r=n(n+1)(2n+1)/6

链接:http://zhidao.baidu.com/link?url=1ocLz44O3omKQVAk22kzGo9C_e74pAb-S-2azNC9Gn-EQljuRKip1Yk7WKt-vtmcTjpJGeoICj8TAa9VWBxGQK

//注意:翻转标记的时候,有些值也会翻转。(这个真的需要吗?数据证明真的需要)

//链接:http://www.cnblogs.com/ianaesthetic/p/4223696.html

关于这道题,写了好久,最后不知道怎么就ac了。(加了第三个代码后就知道为什么以前wr,现在ac了。)

(今天中午在瓜子和葡萄之间,选择了葡萄,好吃,停不下拿葡萄的手,户太八号,真的名不虚传可怜

2015.9.11:

在深刻理解题意后,想到了另一种维护方法:

假设一某个点m为根节点的子树,维护的链是a1,a2,a3……an,

1.在a1到an中任意选择两个点x,y,那么维护将所有的H(x,y)加起来的和;

2.在a1到an中任意选择一个点x,那么维护将所有的H(x,an)加起来的和;

3.在a1到an中任意选择一个点x,那么维护将所有的H(a1,x)加起来的和;

4.维护a1+a2+……+an的和

5.维护以m为根节点的子树中所有点的个数。

(涉及到第3个操作,就要运用代码中的思想。)

wr的代码:

//想错了求期望的方法,想着反正access之后只有左边有,所以只算了左边的,但是左孩子可能//左右都有,但是每棵树追根究底都是维护的一条链,所以splay树上的边并不是现实中的边,不能//在splay树上找两点之间的路径。而是想着,splay树上的点本身是一条链,所以在这条链上左孩//子的点——根节点——右孩子的点,是这样排的,那么期望,就是通过维护那些 a1*1*n+a2*2*(n-1)……#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define N 50010struct node{    node *fa;    node *ch[2];    int val;    int root;    long long int valnum;    long long int add;    long long int rtvsum;    long long int sovsum;    //long long int sum;    int rev;    long long int siz;    void init(int tempval,int tempvalnum){        fa=NULL;        ch[0]=NULL;        ch[1]=NULL;        val=tempval;        root=val;        valnum=tempvalnum;        add=0;        rtvsum=valnum;        sovsum=valnum;        //sum=valnum;        rev=0;        siz=1;    }    bool isroot(){        return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this);    }    void fswitch(){        rev^=1;        swap(ch[0],ch[1]);    }    void push_down(){        if(rev){            rev=0;            if(ch[0]){                ch[0]->fswitch();            }            if(ch[1]){                ch[1]->fswitch();            }        }        if(add){            if(ch[0]){                ch[0]->valnum+=add;                ch[0]->add+=add;                int tempn=ch[0]->siz;                for(int i=tempn;i>=1;i--){                    ch[0]->rtvsum+=i*(tempn+1-i)*add;                }                ch[0]->sovsum+=(1+tempn)*tempn/2*add;                //ch[0]->sum+=add*ch[0]->siz;            }            if(ch[1]){                ch[1]->valnum+=add;                ch[1]->add+=add;                int tempn=ch[1]->siz;                for(int i=tempn;i>=1;i--){                    ch[1]->rtvsum+=i*(tempn+1-i)*add;                }                ch[1]->sovsum+=(1+tempn)*tempn/2*add;                //ch[1]->sum+=add*ch[1]->siz;            }            add=0;        }    }    void go(){        //printf("wo shi da hao ren");调错:无限循环        /*if(this==NULL){            printf("wo shi da hao ren");        }        if(fa==this){            printf("%d ",val);        }*/        if(!isroot()){            fa->go();        }        push_down();        return;    }    int dir(){        return fa->ch[1]==this?1:0;    }    void setedge(int d,node *another){        ch[d]=another;        if(another){            another->fa=this;        }    }    void push_up(){        siz=1;        rtvsum=valnum;        sovsum=valnum;        //sum=valnum;        if(ch[0]){            siz+=ch[0]->siz;            root=ch[0]->root;            rtvsum+=ch[0]->rtvsum+ch[0]->sovsum+valnum*ch[0]->siz;            sovsum+=ch[0]->sovsum+valnum*ch[0]->siz;            //sum+=ch[0]->sum;        }        else{            root=val;        }    }    void rot(){        int d=dir();        node *tempfafa=fa->fa;//调错:什么时候4的fa指向2?        /*if(fa->fa&&val==fa->fa->val){            printf("%d %d\n",val,fa->val);        }*/        if(!(fa->isroot())){            tempfafa->ch[fa->dir()]=this;        }        fa->setedge(d,ch[!d]);        setedge(!d,fa);        fa=tempfafa;        ch[!d]->push_up();        return;    }    void splay(){        go();        while(!isroot()){            if(!(fa->isroot())){                dir()==fa->dir()?fa->rot():rot();            }            rot();//调错:最后是因为在这里使得2的fa指向2            /*if(fa){                if(fa->val==val){                    printf("wo shi da hao ren");                }            }*/        }        push_up();        return;    }    void access(){        for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){            /*printf("%d\n",p->val);            if(p->fa){                printf("%dha\n",p->fa->val);            }*/            p->splay();//调错:是这里出了问题,把2的fa指向了2            /*printf("%d\n",p->val);            if(p->fa){                printf("%dhe\n",p->fa->val);            }*/            p->setedge(1,q);            p->push_up();        }        splay();        return;    }    void make_root(){        access();//调错:样例中 2,3,4 时没回来printf("wo shi da hao ren");        fswitch();        return;    }    void cut(node *another){        make_root();        another->access();        another->ch[0]->fa=NULL;        another->ch[0]=NULL;        another->push_up();        return;    }    void link(node *another){        another->make_root();        another->fa=this;        return;    }    bool islink(node *another){        make_root();//调错:样例中 2,3,4 时这里没回来printf("wo shi da hao ren");        another->access();        if(another->root==this->val){            return true;        }        else{            return false;        }    }    void addnum(node *another,int tempadd){        make_root();        another->access();        another->add+=tempadd;        another->valnum+=tempadd;        for(int i=siz;i>=1;i--){            rtvsum+=i*(siz+1-i)*tempadd;        }        sovsum+=(1+siz)*siz/2*tempadd;        //sum+=siz*tempadd;        return;    }    long long int gcd(long long int a,long long int b){        long long int c;        while(b){            c=a%b;            a=b;            b=c;        }        return a;    }    pair<long long int,long long int> query(node *another){        another->make_root();        access();        /*if(ch[0]){            printf("%d %d %d\n",val,another->val,ch[0]->val);        }*/        pair<long long int,long long int> p;        //long long int tempfirst=rtvsum*2-sum,tempsecond=(1+siz)*siz-siz;        long long int tempfirst=rtvsum,tempsecond=(1+siz)*siz/2;        long long int tempgcd=gcd(tempfirst,tempsecond);        //printf("%lld %lld %lld %lld\n",siz,tempfirst,tempsecond,tempgcd);        p.first=tempfirst/tempgcd;        p.second=tempsecond/tempgcd;        //printf("%lld\n",p.second);        return p;    }};node *tree[N],pool[N];int main(){    int n,m;    int op,a,b,c;    while(scanf("%d%d",&n,&m)!=EOF){        for(int i=1;i<=n;i++){            scanf("%d",&a);            tree[i]=&(pool[i]);            tree[i]->init(i,a);        }        for(int i=1;i<n;i++){            scanf("%d%d",&a,&b);            tree[a]->link(tree[b]);        }        for(int i=0;i<m;i++){            scanf("%d%d%d",&op,&a,&b);//printf("wo shi da hao ren");            if(op==1){                if(tree[a]->islink(tree[b])){//感觉这里的操作或许不符合题意                    tree[a]->cut(tree[b]);//调错:读错题了,把cut写成了link不出结果了一下午。能不能认真读题,敢不敢认真读题                }                //printf("%dha\n",tree[4]->fa->val);            }            else if(op==2){                if(tree[a]->islink(tree[b])){                    //printf("%d %d\n",a,b);                    continue;                }                else{                    //printf("wo shi da hao ren");                    tree[a]->link(tree[b]);                }            }            else if(op==3){                scanf("%d",&c);                if(tree[a]->islink(tree[b])){                    tree[a]->addnum(tree[b],c);                    //调错:addnum这里出现了问题                    //printf("%lld %lld %lld %lld\n",tree[1]->valnum,tree[2]->valnum,tree[3]->valnum,tree[4]->valnum);                }                else{                    continue;                }            }            else{                if(tree[a]->islink(tree[b])){                    pair<long long int,long long int> p=tree[a]->query(tree[b]);                    printf("%lld/%lld\n",p.first,p.second);                }                else{                    printf("-1\n");                }            }        }    }    return 0;}

正确的代码:

//root似乎不对,但是以前用的时候,ac了,为什么?(root指的是,见bzoj2843)#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define N 50010struct node{    node *fa;    node *ch[2];    int rev;    int val;    long long int add;    long long int valnum;    long long int ans;    long long int fsum;    long long int bsum;    long long int sum;    long long int siz;    void init(int tempval,int tempvalnum){//已验证,正确         fa=ch[0]=ch[1]=NULL;        rev=0;        val=tempval;        add=0;        valnum=tempvalnum;        ans=valnum;        fsum=valnum;        bsum=valnum;        sum=valnum;        siz=1;    }    bool isroot(){//已验证,正确         return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this);    }    void fswitch(){//已验证,正确         rev^=1;        swap(ch[0],ch[1]);    swap(fsum,bsum);//注意这里,维护的某些数据在左右子树交换时,也会发生变化,五星级!!!!        return;    }    void fadd(long long int tempadd){//已验证,正确         valnum+=tempadd;        add+=tempadd;        ans+=(siz*siz*siz+3*siz*siz+2*siz)/6*tempadd;        fsum+=(1+siz)*siz/2*tempadd;        bsum+=(1+siz)*siz/2*tempadd;        sum+=siz*tempadd;        return;    }    void push_down(){//已验证,正确         if(rev){            if(ch[0]){                ch[0]->fswitch();            }            if(ch[1]){                ch[1]->fswitch();            }            rev=0;        }        if(add){            if(ch[0]){                ch[0]->fadd(add);            }            if(ch[1]){                ch[1]->fadd(add);            }            add=0;        }        return;    }    void go(){//已验证,正确         if(!isroot()){            fa->go();        }        push_down();        return;    }    int dir(){//已验证,正确         return fa->ch[1]==this?1:0;    }    void setedge(int d,node *another){//已验证,正确         ch[d]=another;        if(another){            another->fa=this;        }    }    void push_up(){//已验证,正确         if(ch[0]&&ch[1]){            ans=ch[0]->ans+ch[0]->fsum*(ch[1]->siz+1)+valnum*(ch[0]->siz+1)*(ch[1]->siz+1)+ch[1]->ans+ch[1]->bsum*(ch[0]->siz+1);            fsum=ch[0]->fsum+ch[1]->fsum+valnum*(ch[0]->siz+1)+ch[1]->sum*(ch[0]->siz+1);            bsum=ch[1]->bsum+ch[0]->bsum+valnum*(ch[1]->siz+1)+ch[0]->sum*(ch[1]->siz+1);            sum=valnum+ch[0]->sum+ch[1]->sum;            siz=ch[0]->siz+ch[1]->siz+1;        }        else if(ch[0]){            ans=ch[0]->ans+ch[0]->fsum+valnum*(ch[0]->siz+1);            fsum=ch[0]->fsum+valnum*(ch[0]->siz+1);            bsum=ch[0]->bsum+ch[0]->sum+valnum;            sum=valnum+ch[0]->sum;            siz=ch[0]->siz+1;        }        else if(ch[1]){            ans=ch[1]->ans+ch[1]->bsum+valnum*(ch[1]->siz+1);            fsum=ch[1]->fsum+ch[1]->sum+valnum;            bsum=ch[1]->bsum+valnum*(ch[1]->siz+1);            sum=valnum+ch[1]->sum;            siz=ch[1]->siz+1;        }        else{            ans=valnum;            fsum=valnum;            bsum=valnum;            sum=valnum;            siz=1;        }        return;    }    void rot(){//已验证,正确         int d=dir();        node *tempfafa=fa->fa;        if(!(fa->isroot())){            tempfafa->ch[fa->dir()]=this;        }        fa->setedge(d,ch[!d]);        setedge(!d,fa);        fa=tempfafa;        ch[!d]->push_up();        return;    }    void splay(){        go();        while(!isroot()){            if(!(fa->isroot())){                dir()==fa->dir()?fa->rot():rot();            }            rot();        }        push_up();        return;    }    void access(){        for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){            p->splay();            p->setedge(1,q);            p->push_up();        }        splay();    }    void make_root(){        access();        fswitch();        return;    }    void cut(node *another){        another->make_root();        access();        ch[0]->fa=NULL;        ch[0]=NULL;        push_up();        return;    }    void link(node *another){        another->make_root();        another->fa=this;        return;    }int find_root(){//用find_root,不要用rootnode *temp=this;while(temp->fa){temp=temp->fa;}return temp->val;}    bool islink(node *another){    return find_root()==another->find_root()?true:false;    }    void addnum(node *another,int tempadd){        another->make_root();        access();        fadd(tempadd);        return;    }    long long int gcd(long long int a,long long int b){        long long int c;        while(b){            c=a%b;            a=b;            b=c;        }        return a;    }    pair<long long int,long long int> query(node *another){        another->make_root();        access();        long long int tempfirst=ans,tempsecond=(1+siz)*siz/2;        long long int tempgcd=gcd(tempfirst,tempsecond);        pair<long long int,long long int> p;        p.first=tempfirst/tempgcd;        p.second=tempsecond/tempgcd;        return p;    }};node *tree[N],pool[N];int main(){    int n,m;    int op,a,b,c;    scanf("%d%d",&n,&m);//只有一组数据    for(int i=1;i<=n;i++){        scanf("%d",&a);        tree[i]=&(pool[i]);        tree[i]->init(i,a);    }    for(int i=1;i<n;i++){        scanf("%d%d",&a,&b);        tree[a]->link(tree[b]);    }    for(int i=0;i<m;i++){        scanf("%d%d%d",&op,&a,&b);        if(op==1){            if(tree[a]->islink(tree[b])){                tree[a]->cut(tree[b]);            }        }        else if(op==2){            if(!(tree[a]->islink(tree[b]))){                tree[a]->link(tree[b]);            }        }        else if(op==3){            scanf("%d",&c);            if(tree[a]->islink(tree[b])){                tree[a]->addnum(tree[b],c);            }        }        else{            if(tree[a]->islink(tree[b])){                pair<long long int,long long int> p=tree[a]->query(tree[b]);                printf("%lld/%lld\n",p.first,p.second);            }            else{                printf("-1\n");//忘了加\n            }        }    }    return 0;}

下面的代码是从wr改成ac,关键点在于数据类型,要把int改成long long int。

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define N 50010 struct node{    node *fa;    node *ch[2];    int rev;    int val;    long long int add;    long long int valnum;    long long int ans;    long long int fsum;    long long int bsum;    long long int sum;    long long int siz;//因为数据范围,siz必须是long long int,忽视了就wr了。所以如果空间允许,管它什么需不需要,全开成long long int,看你还怎么wr,哼!     void init(int tempval,int tempvalnum){        fa=ch[0]=ch[1]=NULL;        rev=0;        val=tempval;        add=0;        valnum=tempvalnum;        ans=valnum;        fsum=valnum;        bsum=valnum;        sum=valnum;        siz=1;    }     bool isroot(){        return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this);    }     void fswitch(){        rev^=1;        swap(ch[0],ch[1]);        swap(fsum,bsum);//真的需要确定这些值的翻转吗?好像以前root也不需要,好像真的需要。         return;    }     void fadd(int tempadd){        valnum+=tempadd;        add+=tempadd;        ans+=(siz*siz*siz+3*siz*siz+2*siz)/6*tempadd;        fsum+=(1+siz)*siz/2*tempadd;        bsum+=(1+siz)*siz/2*tempadd;        sum+=siz*tempadd;         return;    }     void push_down(){        if(rev){            if(ch[0]){                ch[0]->fswitch();            }            if(ch[1]){                ch[1]->fswitch();            }            rev=0;        }         if(add){            if(ch[0]){                ch[0]->fadd(add);            }            if(ch[1]){                ch[1]->fadd(add);            }            add=0;        }         return;    }     void go(){        if(!isroot()){            fa->go();        }        push_down();         return;    }     int dir(){        return fa->ch[1]==this?1:0;    }     void setedge(int d,node *another){        ch[d]=another;        if(another){            another->fa=this;        }    }     void push_up(){        if(ch[0]&&ch[1]){            ans=ch[0]->ans+ch[0]->fsum*(ch[1]->siz+1)+valnum*(ch[0]->siz+1)*(ch[1]->siz+1)+ch[1]->ans+ch[1]->bsum*(ch[0]->siz+1);            fsum=ch[0]->fsum+ch[1]->fsum+valnum*(ch[0]->siz+1)+ch[1]->sum*(ch[0]->siz+1);            bsum=ch[1]->bsum+ch[0]->bsum+valnum*(ch[1]->siz+1)+ch[0]->sum*(ch[1]->siz+1);            sum=valnum+ch[0]->sum+ch[1]->sum;            siz=ch[0]->siz+ch[1]->siz+1;        }        else if(ch[0]){            ans=ch[0]->ans+ch[0]->fsum+valnum*(ch[0]->siz+1);            fsum=ch[0]->fsum+valnum*(ch[0]->siz+1);            bsum=ch[0]->bsum+ch[0]->sum+valnum;            sum=valnum+ch[0]->sum;            siz=ch[0]->siz+1;        }        else if(ch[1]){            ans=ch[1]->ans+ch[1]->bsum+valnum*(ch[1]->siz+1);            fsum=ch[1]->fsum+ch[1]->sum+valnum;            bsum=ch[1]->bsum+valnum*(ch[1]->siz+1);            sum=valnum+ch[1]->sum;            siz=ch[1]->siz+1;        }        else{            ans=valnum;            fsum=valnum;            bsum=valnum;            sum=valnum;            siz=1;        }         return;    }     void rot(){        int d=dir();        node *tempfafa=fa->fa;         if(!(fa->isroot())){            tempfafa->ch[fa->dir()]=this;        }        fa->setedge(d,ch[!d]);        setedge(!d,fa);        fa=tempfafa;        ch[!d]->push_up();         return;    }     void splay(){        go();         while(!isroot()){            if(!(fa->isroot())){                dir()==fa->dir()?fa->rot():rot();            }            rot();        }        push_up();         return;    }     void access(){        for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){            p->splay();            p->setedge(1,q);            p->push_up();        }        splay();    }     void make_root(){        access();        fswitch();         return;    }     void cut(node *another){        another->make_root();        access();        ch[0]->fa=NULL;        ch[0]=NULL;        push_up();         return;    }     void link(node *another){        another->make_root();        another->fa=this;         return;    }     int find_root(){        node *tempfa=this;        int rootnum=val;         while(tempfa->fa){            tempfa=tempfa->fa;            rootnum=tempfa->val;        }         return rootnum;    }     bool islink(node *another){        return find_root()==another->find_root()?true:false;     }     void addnum(node *another,int tempadd){        another->make_root();        access();        fadd(tempadd);         return;    }     long long int gcd(long long int a,long long int b){        long long int c;         while(b){            c=a%b;            a=b;            b=c;        }         return a;    }     pair<long long int,long long int> query(node *another){        another->make_root();        access();         long long int tempfirst=ans,tempsecond=(1+siz)*siz/2;        long long int tempgcd=gcd(tempfirst,tempsecond);        pair<long long int,long long int> p;         p.first=tempfirst/tempgcd;        p.second=tempsecond/tempgcd;         return p;    }}; node *tree[N],pool[N]; int main(){    int n,m;    int op,a,b,c;     scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%d",&a);        tree[i]=&(pool[i]);        tree[i]->init(i,a);    }    for(int i=1;i<n;i++){        scanf("%d%d",&a,&b);        tree[a]->link(tree[b]);    }     for(int i=0;i<m;i++){        scanf("%d%d%d",&op,&a,&b);        if(op==1){            if((tree[a]->islink(tree[b]))/*&&tree[b]->ch[0]->val==tree[a]->val&&!(tree[a]->ch[1])&&!(tree[a]->ch[0])*/){                tree[a]->cut(tree[b]);            }        }        else if(op==2){            if(!(tree[a]->islink(tree[b]))){                tree[a]->link(tree[b]);            }        }        else if(op==3){            scanf("%d",&c);            if(tree[a]->islink(tree[b])){                tree[a]->addnum(tree[b],c);            }        }        else{            if(tree[a]->islink(tree[b])){                pair<long long int,long long int> p=tree[a]->query(tree[b]);                printf("%lld/%lld\n",p.first,p.second);            }            else{                printf("-1\n");            }        }    }        return 0;}


0 0
原创粉丝点击