可以发现旗杆的顺序是没有用的,对于每列,它的答案是它的最大值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. MySQL(四)DQL语言——条件查询

    摘要:条件查询:条件表达式,逻辑表达式,模糊查询,like,通配符,转义字符,escape关键字,between and,in,is null,is not null,安全等于. 条件查询语法: SE ...

  2. 当From窗体中数据变化时,使用代码获取数据库中的数据然后加入combobox中并且从数据库中取得最后的结果

    private void FormLug_Load(object sender, EventArgs e) { FieldListLug.Clear();//字段清除 DI = double.Pars ...

  3. 微服务网关从零搭建——(六)ocelot配置追踪功能

    butterfly 准备工作 首先下载buterfly release版本 解压并通过命令启动:dotnet Butterfly.Web.dll --EnableHttpCollector=true ...

  4. SwiftyUserDefaults对NSUserDefaults的封装扩展

    SwiftyUserDefaults 是对NSUserDefaults的一些封装和扩展,这个库这个只有一个类,操作起来十分简单方便: 这里只有两个步骤来使用SwiftyUserDefaults: st ...

  5. POJ2454——Jersey Politics

    POJ2454——Jersey Politics 题目大意: 在泽西奶牛和荷斯坦奶牛的最新普查中,威斯康星奶牛在谷仓中获得了三个档位. 泽西奶牛目前控制着国家重新分配委员会. 他们想将国家分为三个相当 ...

  6. [Luogu] P3258 [JLOI2014]松鼠的新家

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

  7. Many Equal Substrings CodeForces - 1029A (kmp next数组应用)

    题目大意 题目看样例也能猜到就是输出最短的循环串. 吐槽 明明是div3第一题为啥子还会用到kmp的知识? 解法 这个题仔细看发现是求最长可去除的后缀,也就是说去除跟下一个相同的字符串还能连接起来.这 ...

  8. Xcode 出现Thread 1: signal SIGABRT

    代码语言:C 出现原因:数组初始化时,循环赋值越界. 例 bool type [30]; for (int i = 0;i<100;i++) type = 0;

  9. BZOJ 4976 [Lydsy1708月赛]宝石镶嵌

    [题解] 我们设总共有m个二进制位出现过1,那么如果n-k≥m,显然所有的1都可以出现,那么答案就是把所有的数或起来. 如果n-k<m,那么因为k不超过100,ai不超过1e5,所以n不超过11 ...

  10. 【模板】Lca倍增法

    Codevs 1036 商务旅行 #include<cstdio> #include<cmath> #include<algorithm> using namesp ...