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


posted @ 2015-09-07 17:28  buzhidaohahaha  阅读(223)  评论(0编辑  收藏  举报