splay tree成段更新,成段查询poj3466
线段树入门题,换成splay tree 来搞搞。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std; #define MAXN 200100 long long Add[MAXN];//延迟标记 struct Splay_Tree
{
int cnt, rt;//cnt为节点数,rt == root struct Tree{
long long K;
long long sumk;
int key;//关键字
int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。
int fa, son[];
}T[MAXN]; inline void init()
{
cnt = ;//初始化超级根节点(标记为0的节点)
T[].size = ;
T[].sumk = ;
T[].K = ;
rt = ;
memset(Add,,sizeof(Add));
}
inline void PushUp(int x)
{
T[x].size=T[T[x].son[]].size+T[T[x].son[]].size+T[x].num;
T[x].sumk=T[T[x].son[]].sumk+T[T[x].son[]].sumk+T[x].K;
} inline void PushDown(int x)
{
if(Add[x])
{
if(T[x].son[])//
{
T[T[x].son[]].K += Add[x];
T[T[x].son[]].sumk += T[T[x].son[]].size*Add[x];
Add[T[x].son[]]+=Add[x];
}
if(T[x].son[])
{
T[T[x].son[]].K+=Add[x];
T[T[x].son[]].sumk += T[T[x].son[]].size*Add[x];
Add[T[x].son[]]+=Add[x];
}
Add[x]=;//不管子节点有没有,这层一定往下推,没有子节点相当于标记无效。
}
} inline int Newnode(int key, int fa,int K) //新建一个节点并返回
{
++cnt;
T[cnt].K = T[cnt].sumk = K;
T[cnt].key=key;
T[cnt].num=T[cnt].size=;
T[cnt].fa=fa;
T[cnt].son[]=T[cnt].son[]=;
return cnt;
} inline void Rotate(int x, int p) //0左旋 1右旋
{
int y=T[x].fa;
PushDown(y);//这里是不是必须的,我感觉从小往上不需要往上推
PushDown(x);
T[y].son[!p]=T[x].son[p];
T[T[x].son[p]].fa=y;
T[x].fa=T[y].fa;
if(T[x].fa)
T[T[x].fa].son[T[T[x].fa].son[] == y]=x;
T[x].son[p]=y;
T[y].fa=x;
PushUp(y);
PushUp(x);
} void Splay(int x, int To) //将x节点移动到To的子节点中
{
while(T[x].fa != To)
{
if(T[T[x].fa].fa == To)
Rotate(x, T[T[x].fa].son[] == x);
else
{
int y=T[x].fa, z=T[y].fa;
int p=(T[z].son[] == y);
if(T[y].son[p] == x)
Rotate(x, !p), Rotate(x, p); //之字旋
else
Rotate(y, p), Rotate(x, p); //一字旋
}
}
if(To == ) rt=x;
} int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
{
if(!rt || p > T[rt].size) return ;
int x=rt;
while(x)
{
PushDown(x);
if(p >= T[T[x].son[]].size+ && p <= T[T[x].son[]].size+T[x].num)
break;
if(p > T[T[x].son[]].size+T[x].num)
{
p-=T[T[x].son[]].size+T[x].num;
x=T[x].son[];
}
else
x=T[x].son[];
}
Splay(x, );
return x;
} int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
{
if(!rt) return ;
int x=rt;
while(x)
{
PushDown(x);
if(T[x].key == key) break;
x=T[x].son[key > T[x].key];
}
if(x) Splay(x, );
return x;
} int Prev() //返回根节点的前驱 非重点
{
if(!rt || !T[rt].son[]) return ;
int x=T[rt].son[];
while(T[x].son[])
{
PushDown(x);
x=T[x].son[];
}
Splay(x, );
return x;
} int next() //返回根结点的后继 非重点
{
if(!rt || !T[rt].son[]) return ;
int x=T[rt].son[];
while(T[x].son[])
{
PushDown(x);
x=T[x].son[];
}
Splay(x, );
return x;
} void Insert(int key,int K) //插入key值
{
if(!rt)
rt=Newnode(key, , K);
else
{
int x=rt, y=;
while(x)
{
PushDown(x);
y=x;
if(T[x].key == key)
{
T[x].num++;
T[x].size++;
break;
}
T[x].size++;//既然一定调整
x=T[x].son[key > T[x].key];
}
if(!x)
x = T[y].son[key > T[y].key] = Newnode(key, y, K);
Splay(x, );
}
} void Delete(int key) //删除值为key的节点1个
{
int x=Find(key);
if(!x) return;
if(T[x].num>)
{
T[x].num--;
PushUp(x);
return;
}
int y=T[x].son[];
while(T[y].son[])
y=T[y].son[];
int z=T[x].son[];
while(T[z].son[])
z=T[z].son[];
if(!y && !z)
{
rt=;
return;
}
if(!y)
{
Splay(z, );
T[z].son[]=;
PushUp(z);
return;
}
if(!z)
{
Splay(y, );
T[y].son[]=;
PushUp(y);
return;
}
Splay(y, );
Splay(z, y);
T[z].son[]=;
PushUp(z);
PushUp(y);
} int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<
{
if(!rt) return ;
int x=rt, ret=, y=;
while(x)
{
y=x;
if(T[x].key <= key)
{
ret += T[T[x].son[]].size + T[x].num;
x=T[x].son[];
}
else
x=T[x].son[];
}
Splay(y, );
return ret;
} // 这个删除太丑了
// void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r
// {
// if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤
// int p=Prev();
// if(!Find(r)) Insert(r);
// int q=next();
// if(!p && !q)
// {
// rt=0;
// return;
// }
// if(!p)
// {
// T[rt].son[0]=0;
// PushUp(rt);
// return;
// }
// if(!q)
// {
// Splay(p, 0);
// T[rt].son[1]=0;
// PushUp(rt);
// return;
// }
// Splay(p, q);
// T[p].son[1]=0;
// PushUp(p);
// PushUp(q);
// }
}spt; int main() {
int n,q;
scanf("%d%d",&n,&q);
spt.init();
for(int i=;i<=n;i++)
{
int tmp;
scanf("%d",&tmp);
spt.Insert(i, tmp);
}
for(int i=;i<q;i++)
{
getchar();
char sign;
scanf("%c",&sign);
long long ans=;
if(sign == 'Q')
{
int a,b;
scanf("%d%d",&a,&b);
if(a==b)
{
int id = spt.Find(a);
// mark
ans = spt.T[id].K;
//cout<<spt.T[id].K<<endl;
}
else
{
int ida,idb;
idb = spt.Find(b);//在这题,因为点没有删除,所以点的标号和splaytree中标号一致。
ida = spt.Find(a);//但是有lazy标记,所以还是得找一遍,可以把标记往下推。
spt.Splay(idb, ida);
int idson = spt.T[idb].son[];
//spt.PushDown(idb);
ans = spt.T[idb].K + spt.T[ida].K + spt.T[idson].sumk;
}
printf("%I64d\n",ans);
//cout<<ans<<endl;
}
else
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c); if(a==b)
{
int id = spt.Find(a);
spt.T[id].K += c;
spt.T[id].sumk += c;
// 这个节点的值改变了,还是得往上推
spt.Splay(id, );
}
else
{
int ida,idb;
idb = spt.Find(b);
ida = spt.Find(a); spt.T[ida].K += c;
//spt.T[ida].sumk += c;
spt.T[idb].K += c;
//spt.T[idb].sumk += c; spt.Splay(idb, ida); int idson = spt.T[idb].son[]; if(idson != )
{
spt.T[ idson ].sumk += spt.T[ idson ].size*c;
spt.T[ idson ].K += c;
Add[idson] += c;// 当全局变量来用
spt.Splay(idson, );//还得往上推一下吧
} } }
}
return ;
}
splay tree成段更新,成段查询poj3466的更多相关文章
- POJ 2155 Matrix (二维线段树入门,成段更新,单点查询 / 二维树状数组,区间更新,单点查询)
题意: 有一个n*n的矩阵,初始化全部为0.有2中操作: 1.给一个子矩阵,将这个子矩阵里面所有的0变成1,1变成0:2.询问某点的值 方法一:二维线段树 参考链接: http://blog.csdn ...
- 【线段树成段更新成段查询模板】【POJ3468】A Simple Problem with Integerst
题目大意: 2个操作 A.区间a b 增加 c B 查询a b; 注意事项:1.记住要清除标记 2.查询时要下放标记,但没必要向上更新 线段:自带的,不用建模 区间和性质:sum: /* WA 1次 ...
- POJ 2777 Count Color (线段树成段更新+二进制思维)
题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的 ...
- Codeforces295A - Greg and Array(线段树的成段更新)
题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...
- POJ2155 Matrix 【二维树状数组】+【段更新点查询】
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 17766 Accepted: 6674 Descripti ...
- hdu1754(splay tree 单点更新,成段查询)
题意就是简单的点更新,成段查询. splay tree 果真是常数比较大的log(n)操作. 比线段树还慢了这么多. // // main.cpp // splay // // Created by ...
- HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)
Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree i ...
- [HDOJ4027]Can you answer these queries?(线段树,特殊成段更新,成段查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027 RT,该题要求每次更新是更新所有节点,分别求平方根,查询是求和.昨晚思前想后找有没有一个数学上的 ...
- ACM: Copying Data 线段树-成段更新-解题报告
Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...
随机推荐
- Python标准库 (pickle包,cPickle包)
在之前对Python对象的介绍中 (面向对象的基本概念,面向对象的进一步拓展),我提到过Python“一切皆对象”的哲学,在Python中,无论是变量还是函数,都是一个对象.当Python运行时,对象 ...
- docker入门——镜像简介
什么是docker镜像 Docker镜像是由文件系统叠加而成. 最底端是一个引导文件系统,即bootfs: 这很像典型的Linux/Unix的引导文件系统.Docker用户几乎永远不会和引导文件系统有 ...
- Windows COM Surrogate 已停止工作怎么办
已解决 如何解决"COM Surrogate 已停止工作"问题 悬赏分:15 - 解决时间:2008-7-6 16:55 Vista系统,经常出现这个提示框,烦人. 我试了网上有关 ...
- WRTNode(MT7620n)USB启动总结
一.改动mt7620.dtsi,去掉默认的bootargs,kernel_menuconfig取消buildin的command line 二.kernel_menuconfig增加scsi驱动.US ...
- Selenium webdriver Java 查找元素
1.简单查找 By ID: WebElement element=driver.findElement(By.id("userId")); By Name:WebElement e ...
- ColorSchemer Studio 2 破解
软件介绍: ColorSchemer Studio 2 is a professional color matching application for anyone from hobbyists t ...
- MVC中上传文件大小限制的解决办法
在Web.Config文件中配置限制上传文件大小与时间. 需要在配置文件里面设置文件上传限定的两个属性值:maxAllowedContentLength,maxRequestLength 允许上传文件 ...
- C# 获取当前路径方法(转)
C# 获取当前路径方法 //获取包含清单的已加载文件的路径或 UNC 位置. public static string sApplicationPath = Assembly.GetExecuting ...
- RabbitMQ 学习笔记(一)特点
RabbitMQ 的具体特点 可靠性: RabbitMQ 使用一些机制来保证可靠性, 如持久化.传输确认及发布确认等. 令灵活的路由: 在消息进入队列之前,通过交换器来路由消息.对于典型的路由功能,R ...
- MongoDB在Windows2003上安装配置及使用
本文档适用于MongoDB2.0.1版本在windows2003上的安装.配置,以及使用. 或者根据需要下载最新的稳定版本. 安装:将下载之后的压缩包解压到任意目录即可,本文假设解压到[D:\mong ...