可以发现旗杆的顺序是没有用的,对于每列,它的答案是它的最大值mx*(mx+1)/2

高度由小到大排序旗杆,问题可以转化为在前h行选k个最小的值

考虑激情splay乱搞(我只会splay......)

设树中序遍历第i个点的d值表示当前最后一个旗帜上面的数字为i-1的列的数量

我们可以二分一下求出我们要利用到第几个点x,对于x之前的点,他们的d值都要全部送给后一个点

所以我们可以删掉x这个点,并在最前面加一个点,这就相当于整体向右移动了一位

对于x这个点单独处理,删除前计算出留在x的数目和给x+1的数目,处理完以后再单独添加

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL; struct trnode
{
int f,son[],c,d,s;
}tr[];int trlen,root,cnt;
void update(int x)
{
int lc=tr[x].son[],rc=tr[x].son[];
tr[x].c=tr[lc].c+tr[rc].c+;
tr[x].s=tr[lc].s+tr[rc].s+tr[x].d;
}
void rotate(int x,int w)
{
int f=tr[x].f,ff=tr[f].f;
int R,r; R=f,r=tr[x].son[w];
tr[R].son[-w]=r;
if(r!=)tr[r].f=R; R=ff,r=x;
if(ff!=)
{
if(tr[R].son[]==f)tr[R].son[]=x;
else tr[R].son[]=x;
}
tr[r].f=R; R=x,r=f;
tr[R].son[w]=r;
tr[r].f=R; update(f);
update(x);
}
void splay(int x,int rt)
{
while(tr[x].f!=rt)
{
int f=tr[x].f,ff=tr[f].f;
if(ff==rt)
{
if(tr[f].son[]==x)rotate(x,);
else rotate(x,);
}
else
{
if(tr[f].son[]==x&&tr[ff].son[]==f){rotate(f,);rotate(x,);}
else if(tr[f].son[]==x&&tr[ff].son[]==f){rotate(f,);rotate(x,);}
else if(tr[f].son[]==x&&tr[ff].son[]==f){rotate(x,);rotate(x,);}
else if(tr[f].son[]==x&&tr[ff].son[]==f){rotate(x,);rotate(x,);}
}
}
if(x!=)
{
update(x);
if(rt==)root=x;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~in~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int FindFront()
{
int f=root;
while(tr[f].son[]!=)f=tr[f].son[];
return f;
}
int FindBehind()
{
int f=root;
while(tr[f].son[]!=)f=tr[f].son[];
return f;
}
int findkth(int k)
{
int x=root;k++;
if(k==)return ;
while()
{
int lc=tr[x].son[],rc=tr[x].son[];
if(tr[lc].c>=k)x=lc;
else if(tr[lc].c+<k)k-=tr[lc].c+,x=rc;
else return x;
}
}
//~~~~~~~~~~~~~~~~~~~~Find~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void add(int d,int f,int w)
{
int x=++trlen;
tr[x].f=f;tr[x].c=;tr[x].d=d;tr[x].s=d;
tr[x].son[]=tr[x].son[]=;
if(f!=)tr[f].son[w]=x;
}
void InsInFront(int d)
{
if(root==)add(d,,),root=trlen;
else add(d,FindFront(),);
splay(trlen,);
}
void InsInBehind(int d)
{
if(root==)add(d,,),root=trlen;
else add(d,FindBehind(),);
splay(trlen,);
}
void del(int x)
{
splay(x,);
if(tr[x].son[]==&&tr[x].son[]==)root=;
else if(tr[x].son[]!=&&tr[x].son[]==){root=tr[x].son[];tr[root].f=;}
else if(tr[x].son[]==&&tr[x].son[]!=){root=tr[x].son[];tr[root].f=;}
else
{
int y=tr[x].son[];
while(tr[y].son[]!=)y=tr[y].son[];
splay(y,x); int R=y,r=tr[x].son[];
tr[R].son[]=r;
tr[r].f=R; root=y;tr[root].f=;
update(y);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~out~~~~~~~~~~~~~~~~~~~~~~~~~ //----------------------------------------------------------------------------------------------- LL ans,cc;
void dfs(int x)
{
if(tr[x].son[]!=)dfs(tr[x].son[]);
ans+=(cc-)*cc/*tr[x].d;cc++;
if(tr[x].son[]!=)dfs(tr[x].son[]);
} struct node{int h,k;}a[];
bool cmp(node n1,node n2){return n1.h<n2.h;}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d%d",&a[i].h,&a[i].k);
sort(a+,a+n+,cmp);
a[].h=; trlen=,root=;
tr[].f=;tr[].c=;tr[].d=;tr[].s=;
tr[].son[]=tr[].son[]=;
InsInFront();cnt=;
for(int i=;i<=n;i++)
{
int fr=FindFront();
tr[fr].d+=a[i].h-a[i-].h;
splay(fr,); int l=,r=cnt,k;
while(l<=r)
{
int mid=(l+r)/;
int x=findkth(mid);splay(x,);
if(tr[tr[x].son[]].s+tr[x].d>=a[i].k)
{
r=mid-;
k=mid;
}
else l=mid+;
} int x=findkth(k-);splay(x,);
int s2=a[i].k-tr[tr[x].son[]].s-tr[x].d;//送给后一个点的值
if(k==cnt)cnt++,InsInBehind(s2);
else
{
int y=findkth(k+);
tr[y].d+=s2;splay(y,);
} x=findkth(k);
int s1=tr[x].d-s2;//留给自己的值
del(x);InsInFront();
x=findkth(k);
tr[x].d+=s1;splay(x,);
} ans=;cc=;dfs(root);
printf("%lld\n",ans);
return ;
}

bzoj1805: [Ioi2007]Sail 船帆的更多相关文章

  1. BZOJ1805[Ioi2007]Sail船帆——线段树+贪心

    题目描述 让我们来建造一艘新的海盗船.船上有 N个旗杆,每根旗杆被分成单位长度的小节.旗杆的长度等于它被分成的小节的数目.每根旗杆上会挂一些帆,每张帆正好占据旗杆上的一个小节.在一根旗杆上的帆可以任意 ...

  2. BZOJ.1805.[IOI2007]sail船帆(贪心 线段树)

    BZOJ 洛谷 首先旗杆的顺序没有影响,答案之和在某一高度帆的总数有关.所以先把旗杆按高度排序. 设高度为\(i\)的帆有\(s_i\)个,那么答案是\(\sum\frac{s_i(s_i-1)}{2 ...

  3. [BZOJ 1805] Sail 船帆

    Link: BZOJ 1805 传送门 Solution: 一道思路比较巧的线段树的题目 首先可以发现,答案和顺序是没有关系的,都是$\sum_{i=1}^n {H_i∗(H_i−1)/2}$. 那么 ...

  4. [IOI2007] sails 船帆

    显然答案与杆的顺序无关(按每个高度考虑). 从高到低考虑杆,设此时的状态为\(S\),\(S[i]\)是高度\(i\)的帆的数目,初始全为\(0\),当前杆的高度为\(h\),杆上需要放置的帆的数目为 ...

  5. luoguP4647 [IOI2007] sails 船帆

    https://www.luogu.org/problemnew/show/P4647 首先发现答案与顺序无关,令 $ x_i $ 表示高度为 $ i $ 的那一行帆的个数,第 $ i $ 行对答案的 ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  7. sail.js学习 - 安装篇

    导言: 最近在学习sails.js(http://sailsjs.org/),因为用的人不多,资料较少,故写些自己的学习过程.因自己也是初学node.js,有问题大家指出. 介绍: sails.js的 ...

  8. Codeforces Round #180 (Div. 2) B. Sail 贪心

    B. Sail 题目连接: http://www.codeforces.com/contest/298/problem/B Description The polar bears are going ...

  9. [Ioi2007]Miners 矿工配餐(BZOJ1806)

    [Ioi2007]Miners 矿工配餐 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 214  Solved: 128 Description 现有两 ...

随机推荐

  1. Flask框架 之重定向、cookie和session

    一.URL重定向(redirect) @app.route("/login") def login(): # 使用url_for函数通过视图函数的名字找到url路径 url = u ...

  2. sort 排序 自定义排序算法的使用

    // struct sort_by_pt// {// bool operator()(const std::pair<CString, AcGePoint3d> a, const std: ...

  3. 梦想MxWeb3D协同设计平台 2019.02.28更新

    梦想MxWeb3D协同设计平台 2019.02.28更新 SDK开发包下载地址: http://www.mxdraw.com/ndetail_10130.html 在线演示网址: http://www ...

  4. java虚拟机(九)--常用jvm参数

    1.-Xms20M: 表示设置JVM启动内存的最小值为20M,必须以M为单位 2.-Xmx20M: 表示设置JVM启动内存的最大值为20M,必须以M为单位.将-Xmx和-Xms设置为一样可以避免JVM ...

  5. 10Java Server Pages 隐式对象

    Java Server Pages 隐式对象 JSP隐式对象是Web容器加载的一组类的实例,它不像一般的Java对象那样用“new”去获取实例,而是可以直接在JSP页面使用的对象.JSP提供的隐式对象 ...

  6. orb slam2

  7. KOA的简易模板引擎实现方式

    上上一期链接--也就是本文的基础,参考KOA,5步手写一款粗糙的web框架 上一期链接--有关Router的实现思路,这份Koa的简易Router手敲指南请收下 本文参考仓库:点我 上一期科普了Rou ...

  8. 12Cookie、Session

    12Cookie.Session-2018/07/24 1.保存会话数据 cookie客户端技术,把每个用户的数据以cookie的形式写给用户各自的浏览器 HttpSession服务端技术,服务器运行 ...

  9. java 十三周总结

  10. 使用Mybatis的逆向工程自动生成代码

    1.逆向工程的作用 Mybatis 官方提供了逆向工程,可以针对数据库表自动生成Mybatis执行所需要的代码(包括mapper.xml.Mapper.java.pojo). 2.逆向工程的使用方法 ...