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