2333?

先记一下吧,这题现在全部都是照着题解做的,因为怎么改都改不出来,只好对着题解改,以后还要再做过

以后再也不用指针了!太恶心了!空指针可不止直接特判那么简单啊,竟然还要因为空指针写奇怪的分类讨论!

没错,就是那个诡异的55和63行。由于要返回删除x后x所在树的新根,要分类讨论:如果x是根且其两个子节点合并后为空,那么去掉x后新树树根为空;如果x是根且其两个子节点合并后不为空,那么去掉x后新树树根为两个子节点合并后的;如果x不是根,那么去掉x后新树树根为原来的find(x)。

另外,打了注释号的(不管是空注释还是被注释掉的语句)都表示此处出过错

 #include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
multiset<int> sx;
void erase(int x)
{
//if(sx.find(x)!=sx.end())
sx.erase(sx.find(x));
}
struct Node
{
int data;int addv;
Node *ch[],*fa;
void pd()
{
if(addv)
{
if(ch[]) ch[]->addv+=addv,ch[]->data+=addv;
if(ch[]) ch[]->addv+=addv,ch[]->data+=addv;
addv=;//
}
}
}nodes[];
Node* find(Node* x)//
{
if(x==NULL) return x;//
while(x->fa) x=x->fa;
return x;
}
Node* merge(Node* a,Node* b)
{
if(!a) return b;
if(!b) return a;
//a->pd();b->pd();
if(a->data < b->data) swap(a,b);
a->pd();
a->ch[]=merge(a->ch[],b);
if(a->ch[])/**/ a->ch[]->fa=a;
swap(a->ch[],a->ch[]);
return a;
}
Node *q[];int q_num;
void solvetag(Node *x)//
{
while(x)q[++q_num]=x,x=x->fa;
//while(x->fa)q[++q_num]=x,x=x->fa;
while(q_num)q[q_num--]->pd();
}
Node* del(Node *x)//删除x,将x较大的儿子提上来,并返回它所在集合的新根节点
{
//if(x==NULL) return x;//''
solvetag(x);
Node *t=merge(x->ch[],x->ch[]),*f=x->fa,*rt;
rt=find(x);if(rt==x) rt=NULL;//
x->ch[]=x->ch[]=x->fa=NULL;
if(f)//
{
if(x==f->ch[]) f->ch[]=t;
else f->ch[]=t;
}
if(t)/**/ t->fa=f;
if(t) rt=find(t);//
return rt;
}
void add(Node *x,int val)
{
//if(x==NULL) return;
solvetag(x);
erase(find(x)->data);
//find(x)->data+=val;
x->data+=val;Node *t=del(x);
sx.insert(merge(x,t)->data);//puts("t1");
}
void hadd(Node *x,int val)
{
//if(x==NULL) return;//'
Node *p=find(x);
erase(p->data);
p->addv+=val;p->data+=val;
sx.insert(p->data);
}
int n,m,addx,Q;
char tmp[];
int main()
{
int i,t,x,y,v;Node *fx,*fy;
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d",&t);
nodes[i].data=t;
//nodes[i].upd();
sx.insert(t);
}
scanf("%d",&Q);
//int axx=0;
while(Q--)
{
scanf("%s",tmp);
if(tmp[]=='U')
{
scanf("%d%d",&x,&y);
fx=find(nodes+x);fy=find(nodes+y);
if(fx==fy) continue;
//solvetag(nodes+x);solvetag(nodes+y);
if(merge(fx,fy)==fx) erase(fy->data);
else erase(fx->data);
}
else if(tmp[]=='A')
{
if(tmp[]=='')
{
scanf("%d%d",&x,&v);
add(nodes+x,v); }
else if(tmp[]=='')
{
scanf("%d%d",&x,&v);
hadd(nodes+x,v);
}
else if(tmp[]=='')
{
scanf("%d",&v);
addx+=v;
}
}
else if(tmp[]=='F')
{
//axx++;
//if(axx==54) printf(" %c ",tmp[1]);
if(tmp[]=='')
{
scanf("%d",&x);
solvetag(nodes+x);
printf("%d\n",nodes[x].data+addx);
}
else if(tmp[]=='')
{
scanf("%d",&x);
//solvetag(nodes+x);
printf("%d\n",find(nodes+x)->data+addx);
}
else if(tmp[]=='')
{
printf("%d\n",*(--sx.end())+addx);
} }
}
return ;
}

另外:本来是想不到去写斜堆的,因为斜堆并不保证任何意义上的平衡,如果用这个在节点上维护附加信息,那么标记传递还有找根什么的复杂度应该是假的。然而实际应用发现...并没有问题?仍然不会分析

另外:把堆合并改成非旋treap里面的样子,也可以过,而且用时几乎完全一样(只差几ms)(然而去掉swap两个子节点就不能了,或者将非旋treap合并里面一些对正确性无关紧要的东西乱改一下也不行,这次跟洛谷上某道可并堆模版不一样了...),说明非旋treap里面堆合并跟一般斜堆合并写法本质应该没有区别(只是保证中序遍历不变)。然而并不会分析?

另外:虽然不交换是错的,但是随机怎么摆却是对的!实际效果是只比斜堆慢了一点点。而且,即使斜堆真的会被卡随机堆也不可能被卡...应该吧

就比如这样

 #include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
multiset<int> sx;
inline int rd()
{
static int x=;
return x=(48271LL*x+)%;
}
void erase(int x)
{
//if(sx.find(x)!=sx.end())
sx.erase(sx.find(x));
}
struct Node
{
int data;int addv;
Node *ch[],*fa;
void pd()
{
if(addv)
{
if(ch[]) ch[]->addv+=addv,ch[]->data+=addv;
if(ch[]) ch[]->addv+=addv,ch[]->data+=addv;
addv=;//
}
}
}nodes[];
Node* find(Node* x)//
{
if(x==NULL) return x;//
while(x->fa) x=x->fa;
return x;
}
Node* merge(Node* a,Node* b)
{
if(!a) return b;
if(!b) return a;
//a->pd();b->pd();
if(a->data < b->data) swap(a,b);
a->pd();
if(rd()%)
{
a->ch[]=merge(a->ch[],b);
if(a->ch[]) a->ch[]->fa=a;
}
else
{
a->ch[]=merge(a->ch[],b);
if(a->ch[]) a->ch[]->fa=a;
}
return a; }
Node *q[];int q_num;
void solvetag(Node *x)//
{
while(x)q[++q_num]=x,x=x->fa;
//while(x->fa)q[++q_num]=x,x=x->fa;
while(q_num)q[q_num--]->pd();
}
Node* del(Node *x)//删除x,将x较大的儿子提上来,并返回它所在集合的新根节点
{
//if(x==NULL) return x;//''
solvetag(x);
Node *t=merge(x->ch[],x->ch[]),*f=x->fa,*rt;
rt=find(x);if(rt==x) rt=NULL;//
x->ch[]=x->ch[]=x->fa=NULL;
if(f)//
{
if(x==f->ch[]) f->ch[]=t;
else f->ch[]=t;
}
if(t)/**/ t->fa=f;
if(t) rt=find(t);//
return rt;
}
void add(Node *x,int val)
{
//if(x==NULL) return;
solvetag(x);
erase(find(x)->data);
//find(x)->data+=val;
x->data+=val;Node *t=del(x);
sx.insert(merge(x,t)->data);//puts("t1");
}
void hadd(Node *x,int val)
{
//if(x==NULL) return;//'
Node *p=find(x);
erase(p->data);
p->addv+=val;p->data+=val;
sx.insert(p->data);
}
int n,m,addx,Q;
char tmp[];
int main()
{
int i,t,x,y,v;Node *fx,*fy;
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d",&t);
nodes[i].data=t;
//nodes[i].upd();
sx.insert(t);
}
scanf("%d",&Q);
//int axx=0;
while(Q--)
{
scanf("%s",tmp);
if(tmp[]=='U')
{
scanf("%d%d",&x,&y);
fx=find(nodes+x);fy=find(nodes+y);
if(fx==fy) continue;
//solvetag(nodes+x);solvetag(nodes+y);
if(merge(fx,fy)==fx) erase(fy->data);
else erase(fx->data);
}
else if(tmp[]=='A')
{
if(tmp[]=='')
{
scanf("%d%d",&x,&v);
add(nodes+x,v); }
else if(tmp[]=='')
{
scanf("%d%d",&x,&v);
hadd(nodes+x,v);
}
else if(tmp[]=='')
{
scanf("%d",&v);
addx+=v;
}
}
else if(tmp[]=='F')
{
//axx++;
//if(axx==54) printf(" %c ",tmp[1]);
if(tmp[]=='')
{
scanf("%d",&x);
solvetag(nodes+x);
printf("%d\n",nodes[x].data+addx);
}
else if(tmp[]=='')
{
scanf("%d",&x);
//solvetag(nodes+x);
printf("%d\n",find(nodes+x)->data+addx);
}
else if(tmp[]=='')
{
printf("%d\n",*(--sx.end())+addx);
} }
}
return ;
}

我差点忘了一件事,就是相同权值的在堆里顺序无所谓,merge两个参数先后也是无所谓的。

bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作的更多相关文章

  1. 洛谷P3273 [SCOI2011] 棘手的操作 [左偏树]

    题目传送门 棘手的操作 题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 ...

  2. 洛谷P3273 [SCOI2011]棘手的操作

    题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权 ...

  3. BZOJ2330或洛谷3275 [SCOI2011]糖果

    BZOJ原题链接 洛谷原题链接 很明显的差分约束,但数据范围较大,朴素\(SPFA\)判正环求解会\(T\)(理论上如此,但我看到有挺多人用朴素的还跑得挺快..),所以需要优化. 我们所建立的有向图中 ...

  4. 洛谷P3275 [SCOI2011]糖果(差分约束,最长路,Tarjan,拓扑排序)

    洛谷题目传送门 差分约束模板题,等于双向连0边,小于等于单向连0边,小于单向连1边,我太蒻了,总喜欢正边权跑最长路...... 看遍了讨论版,我是真的不敢再入复杂度有点超级伪的SPFA的坑了 为了保证 ...

  5. AC日记——[HAOI2015]树上操作 洛谷 P3178

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  6. bzoj2333 [SCOI2011]棘手的操作(洛谷3273)

    题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权 ...

  7. 洛谷.3273.[SCOI2011]棘手的操作(左偏树)

    题目链接 还是80分,不是很懂. /* 七个操作(用左偏树)(t2表示第二棵子树): 1.合并:直接合并(需要将一个t2中原有的根节点删掉) 2.单点加:把这个点从它的堆里删了,加了再插入回去(有负数 ...

  8. 【POJ 3159】Candies&&洛谷P3275 [SCOI2011]糖果

    来补一下自己很久以前那个很蒟蒻很蒟蒻的自己没有学懂的知识 差分约束,说白了就是利用我们在求最短路的一个\(relax\)操作时的判断的原理 \[dis[v]>dis[u]+disj(u,v)\] ...

  9. bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572

    记一下:线段树占空间是$2^{ceil(log2(n))+1}$ 这个就是一个线段树区间操作题,各种标记的设置.转移都很明确,只要熟悉这类题应该说是没有什么难度的. 由于对某区间set之后该区间原先待 ...

随机推荐

  1. struts2 自己定义表单

    自己定义表单一定会涉及<s:iterator/>迭代,一个复杂的自己定义表单可能会嵌套n多层迭代. 比方一个自己定义一个问卷调查页面涉及3个模型:一个Survey代表一个调查.一个Page ...

  2. CentOS 5 全功能服务器搭建

    转自: http://www.php-oa.com/2007/12/27/centos-www.html 转:主要做为历史记录,以后用.另外很少见这么好的编译的文章,其实我不推荐用编译安装.但这个文章 ...

  3. Fortinet网络接入及安全方案配置步骤

    http://sec.chinabyte.com/200/12553700.shtml 1.概述: Fortinet无线接入及方案由以下两类设备组成: AC(Wifi接入控制器)及安全网关:Forti ...

  4. notepad++ 查找引用(Find Reference)(适用于c c++及各类脚本比方lua、python等)

    在程序开发过程中,程序猿经经常使用到的一个功能就是查找引用(Find Reference).Visual Studio里面的相应功能是"查找全部引用"(Find All Refer ...

  5. [IT新应用]无线投影技术

    会议室内投影时,经常会有笔记本与投影仪之间因兼容性等无法切换的现象. 了解了下,无线投影方案的厂家大致如下: 1.http://www.taco.net.cn/ 2.巴可无线投影 https://ww ...

  6. 利用chrome调试手机网页

    1.pc端安装最新的chrome 2.手机端安装最新的chrome ( Android机 )ms不需要 3.USB连接线 4.打开电脑的chrome 在地址栏输入 chrome://inspect

  7. 设计模式-(16)模版模式 (swift版)

    一,概念: 定义一个算法中的操作框架,而将一些步骤延迟到子类中.使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤.(Define the skeleton of an algorithm i ...

  8. mysql16---读写分离

    读写分离(负载平衡)(读写分离肯定要用到主从复制) 如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散. 分表不能解决并发量大的问题. Sql语句发过来 ...

  9. YTU 2918: Shape系列-5

    2919: Shape系列-5 时间限制: 1 Sec  内存限制: 128 MB 提交: 251  解决: 199 题目描述 JC和Kitty听说小亮和小华有了Rectangle和Circle并用R ...

  10. 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)

    几大最短路径算法比较 几个最短路径算法的比较:Floyd        求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3).       Floy ...