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