bzoj2759
感觉要去算题,而不是让题算我。还记得郑渊洁童话中,有一句话是要俯视知识,而不是在海洋里挣扎。
今天才注意到ppt里的一句话:
动态树!=lct,lct只是解决动态树问题的一种数据结构
ppt链接:http://wenku.baidu.com/view/a611cec4dd3383c4bb4cd2d8.html
(在机房搜索一个悬疑小说的结局,结果出来一大堆奇怪的网页,关键是机房还有其他人,好尴尬,全身冒冷汗。,怎么看个小说就那么难呢?)
编译时出现:multiple types in one declaration。(c++用的还不是很擅长,得慢慢积累。)
链接:http://blog.csdn.net/runboying/article/details/7525920,但是这个也是转自http://hi.baidu.com/%B2%A4%C2%DC%C3%D7%BE%C6/blog/item/7c4ab1da9b4ac3f438012f66.html,不过后面这个已经搬家了。
代码参考:http://blog.csdn.net/popoqqq/article/details/40436165
这道题写了很久很久,久到我已经看完了两部半小说。改到面目全非,终于ac了,此时此景,怎能不让人想起一首《好日子》。
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define N 30010//应该不是空间开的太小 #define MOD 10007 struct line{ int k,b; line operator +(line another){ line ans; /*if(this!=NULL){//调错,k出了问题,b也出了问题,但是他this!=NULL printf("wo shi da hao ren"); } printf("%d\n",b); printf("%d\n",another.k);*/ ans.k=/*(*/(another.k*k)%MOD/*+MOD)%MOD*/; ans.b=/*(*/(another.k*b%MOD+another.b)%MOD/*+MOD)%MOD*/; return ans; } pair<int,int> fexgcd(int x,int y){//不是这里导致的超时 pair<int,int> p; if(y==0){ p.first=1; p.second=/*1*/0; } else{ int temp=x/y; pair<int,int> tempp=fexgcd(y,x%y); p.first=tempp.second; p.second=/*((*/tempp.first-tempp.second*temp/*%MOD)%MOD+MOD)%MOD*/; } return p; } int exgcd(){//看来接下来需要练下数论,不是这里导致的超时 //printf("%d %dhahaha\n",k,b); if(k==1){ if(b==0){//这里如果b==0的话,在[0,10007)范围内就不仅仅有一个答案了。 return -2; } else{ //printf("wo shi da hao ren"); return -1; } } else{ return ((MOD-b)*(fexgcd((k-1+MOD)%MOD,MOD).first%MOD+MOD)%MOD)%MOD;//根据题中所给的数据可知,此时在[0,10007)之间有且仅有一个答案。所以要具体题 } } }; struct node{//有向树不用make_root,所以没有rev node *fa; node *sfa; node *ch[2]; line num; line sum; void init(int tempk,int tempb){ fa=sfa=ch[0]=ch[1]=NULL; sum.k=num.k=tempk; sum.b=num.b=tempb;//这里sum是默认的x[this]用x[fa]表示,虽然这里fa还没赋值。 } bool isroot(){ /*if(this==NULL){ printf("wo shi da hao ren");//这里输出了 }*/ return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this); } int dir(){ return fa->ch[1]==this?1:0; } void setedge(int d,node *another){ ch[d]=another; if(another){ another->fa=this; } /*node *temproot=find_root(); printf("%d\n",temproot->num.b); temproot=find_root(); printf("%d\n",temproot->num.b); printf("wo shi da hao ren\n");*/ } void push_up(){//这里没有讨论ch[0],ch[1]存不存在,就直接进行了运算,如果有个自己定义的null就可以避免这种情况,但是那种真的好麻烦,那么就应该把这种用好。 if(ch[0]&&ch[1]){ sum=ch[0]->sum+num+ch[1]->sum; } else if(ch[0]){ sum=ch[0]->sum+num; } else if(ch[1]){ sum=num+ch[1]->sum; } else{ sum=num; } 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();//这里少了ch[!d]-> /*node *temproot=find_root(); printf("%d\n",temproot->num.b); temproot=find_root(); printf("%d\n",temproot->num.b); printf("wo shi da hao ren\n");*/ return; } void splay(){ /*if(this==NULL){//这里输出了 printf("wo shi da hao ren"); }*/ while(!isroot()){ if(!(fa->isroot())){//是这里面原树的根节点发生了变化 dir()==fa->dir()?fa->rot():rot(); } /*node *temproot=find_root(); printf("%d\n",temproot->num.b); temproot=find_root(); printf("%d\n",temproot->num.b); printf("wo shi da hao ren\n");*/ rot(); } //printf("wo shi da hao ren"); push_up();//这里没有输出 //printf("wo bu shi da huai dan"); return; } void access(){ /*if(this==NULL){//这里输出了 printf("wo shi da hao ren"); }*/ for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){//可能是这里导致的超时 //printf("wo shi da hao ren"); p->splay();//这里没有输出 //printf("wo bu shi da huai dan"); p->setedge(1,q); p->push_up(); } splay();//经过这一步,原树的根节点才发生了变化 /*node *temproot=find_root(); printf("%d\n",temproot->num.b);*/ return; } /*void cut(node *another){//因为这里是有向树,所以执行cut时,能确定那个点是父节点,那个点是根节点,所以就不用make_root()了,并且因为是有向树,所以也不能make_root() another->access(); another->ch[0]->fa=NULL; another->ch[0]=NULL; another->push_up(); return; } void link(node *another){//因为这里是有向树,所以要求连接两个点时,能确定another必定是它所在子树的根节点,所以another就不用make_root()了 another->fa=this; }*/ node *find_root(){//这个函数在这里是找原树的根节点,而不是找原树的根节点所在的那棵splay树的根节点。 access(); /*node *temp=this; while(temp->fa){ temp=temp->fa; }*/ node *temp=this;//不是这里导致的超时 while(temp->ch[0]){ temp=temp->ch[0]; } return temp; } /*bool islink(node *another){ return find_root()==another->find_root()?true:false; }*/ int query(){ node *root=find_root(); int tempans; /*if(root->sfa==NULL){//这里输出了 printf("wo shi da hao ren"); } printf("%d\n",root->num.b);*/ root->sfa->access();//re不是因为这里 /*node *temproot=find_root();//经过这里原树的根节点发生了变化 printf("%d\n",temproot->num.b); printf("wo shi da hao ren");*///这里没有输出 tempans=root->sfa->sum.exgcd(); if(tempans==-1||tempans==-2){ return tempans; } else{ access(); return ((tempans*sum.k+MOD)%MOD+sum.b)%MOD; } } void modify(int tempk,node *another,int tempb){//可能是这里导致的re node *root=find_root();//不是这里倒是的re //access();//不是这里导致的re,因为find_root()里已经access了,所以这里可以省去 if(ch[0]){//可能modify根节点,所以ch[0]可能不存在,以前没注意过,现在要注意。不是这里倒是的re ch[0]->fa=NULL; ch[0]=NULL; } num.k=tempk;//这里不用给sum赋值,因为后面有push_up,但是正因为后面有push_up,所以即使赋值也没什么问题 num.b=tempb; push_up(); if(root==this){ sfa=NULL; } else if(root->sfa->find_root()!=root){//应该是这里导致的re root->access();//这里root要access一下,否则re root->fa=root->sfa; root->sfa=NULL; } access();//同理,这里也要access一下,否则re if(another->find_root()==this){ this->sfa=another; } else{ this->fa=another; } return; /*node *root=find_root(); if(ch[0]){ ch[0]->fa=NULL; ch[0]=NULL; } num.k=tempk; num.b=tempb; push_up(); if(root==this){ sfa=NULL; } else{ if(root->sfa->find_root()!=root){ root->access(); root->fa=root->sfa; root->sfa=NULL; } } access(); if(another->find_root()==this){ sfa=another; } else{ fa=another; } return;*/ } }; node *tree[N],pool[N]; int fa[N]; int vis[N]; int tot; void dfs(int u){//这段很重要 vis[u]=tot; if(vis[fa[u]]==tot){ tree[u]->sfa=tree[fa[u]]; } else{ tree[u]->fa=tree[fa[u]]; if(!vis[fa[u]]){//如果fa[u]没有dfs过,才dfs dfs(fa[u]); } } return; } int main(){ int n; int q; int a,b,c,d; char op[10]; scanf("%d",&n); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ tree[i]=&(pool[i]); scanf("%d%d%d",&a,&b,&c); tree[i]->init(a,c); fa[i]=b; } tot=0; for(int i=1;i<=n;i++){ if(!vis[i]){ tot++; dfs(i); } } scanf("%d",&q); for(int i=0;i<q;i++){//find_root找的不是原树的根节点,而是包含原树根节点的那棵splay树的根节点 //printf("%d\n",tree[1]->find_root()->num.b);//在样例中第一次输出5,第二次输出1 scanf("%s",op); if(op[0]=='A'){ scanf("%d",&a); printf("%d\n",tree[a]->query()); } else{ scanf("%d%d%d%d",&a,&b,&c,&d); tree[a]->modify(b,tree[c],d); } } return 0; }
自己用重写了一遍,因为前一遍太不堪入目了。
//每个节点维护的值,是最后我需要的值,并且在lct的变化过程中能始终正确维护的值 //在这道题中并没有记录具体的数值,只不过记录了数据之间的关系,就足够了。 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define N 30010 #define MOD 10007 struct line{ int k,b; line operator +(line another){//another用this表示 line ans; ans.k=(another.k*k%MOD+MOD)%MOD; ans.b=(((another.k*b%MOD+MOD)%MOD+another.b)%MOD+MOD)%MOD; return ans; } pair<int,int> exgcd(int x,int y){ if(!y){ return make_pair(1,1); } else{ pair<int,int> temp=exgcd(y,x%y); return make_pair(temp.second,((temp.first-(x/y*temp.second%MOD+MOD)%MOD)%MOD+MOD)%MOD); } } int query(){ if(k==1){ if(b==0){ return -2; } else{ return -1; } } else{ return ((-b)*exgcd(((k-1)%MOD+MOD)%MOD,MOD).first%MOD+MOD)%MOD; } } };//记得加分号 struct node{ node *sfa,*fa; node *ch[2]; line num,sum; void init(int tempk,int tempb){ sfa=fa=ch[0]=ch[1]=NULL; num.k=sum.k=tempk; num.b=sum.b=tempb; return; } bool isroot(){ return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this); } int dir(){ return fa->ch[1]==this?1:0; } void setedge(int d,node *another){ ch[d]=another; if(another){ another->fa=this; } return; } void push_up(){ if(ch[0]&&ch[1]){ sum=ch[0]->sum+num+ch[1]->sum; } else if(ch[0]){ sum=ch[0]->sum+num; } else if(ch[1]){ sum=num+ch[1]->sum; } else{ sum=num; } 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(){ while(!isroot()){ if(!(fa->isroot())){ dir()==fa->dir()?fa->rot():rot(); } rot(); } push_up(); return; } void access(){ for(node *p=this,*q=NULL;p;q=p,p=p->fa){ p->splay(); p->setedge(1,q); p->push_up(); } splay(); } node *find_root(){ node *temp=this; access(); while(temp->ch[0]){ temp=temp->ch[0]; } return temp; } int query(){ node *root=find_root(); int tempans; root->sfa->access(); tempans=root->sfa->sum.query(); if(tempans==-1||tempans==-2){ return tempans; } else{ access(); return (sum.k*tempans%MOD+sum.b)%MOD; } } void modify(int tempk,node *another,int tempb){ node *root=find_root(); access(); num.k=tempk; num.b=tempb; if(ch[0]){ ch[0]->fa=NULL; ch[0]=NULL; } push_up(); if(root==this){ sfa=NULL; } else if(root->sfa->find_root()!=root){ root->access();//此时虽然不一定要求让root成为它所在树的根节点,但是还是要access一下,这样它的fa就是NULL了 root->fa=root->sfa; root->sfa=NULL; } if(another->find_root()==this){ sfa=another; } else{ access();//与上面同理,如果没有会re fa=another; } return; } }; node *tree[N],pool[N]; int vis[N],fa[N]; int tot; void dfs(int u){ vis[u]=tot; if(vis[fa[u]]==tot){ tree[u]->sfa=tree[fa[u]]; return; } else{ tree[u]->fa=tree[fa[u]]; if(!vis[fa[u]]){ dfs(fa[u]); } } return; } int main(){ int n,q; int a,b,c,d; char op[10]; scanf("%d",&n); memset(vis,0,sizeof(vis)); tot=0; for(int i=1;i<=n;i++){ scanf("%d%d%d",&a,&b,&c); tree[i]=&(pool[i]); tree[i]->init(a,c); fa[i]=b; } for(int i=1;i<=n;i++){ if(!vis[i]){ tot++; dfs(i); } } scanf("%d\n",&q); for(int i=0;i<q;i++){ scanf("%s",op); if(op[0]=='A'){ scanf("%d",&a); printf("%d\n",tree[a]->query()); } else{ scanf("%d%d%d%d",&a,&b,&c,&d); tree[a]->modify(b,tree[c],d); } } return 0; }