您的位置:首页 > 其它

bzoj2759

2015-09-07 17:28 423 查看
感觉要去算题,而不是让题算我。还记得郑渊洁童话中,有一句话是要俯视知识,而不是在海洋里挣扎。

今天才注意到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
,pool
;
int fa
;
int vis
;
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
,pool
;
int vis
,fa
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: