bzoj3091

这道题加深了对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 50010

struct 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 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;

    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,不要用root
		node *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;
}


posted @ 2015-09-01 21:05  buzhidaohahaha  阅读(240)  评论(0编辑  收藏  举报