设为首页 加入收藏

TOP

[IOI2007] sails 船帆
2019-03-19 14:09:27 】 浏览:60
Tags:IOI2007 sails 船帆

显然答案与杆的顺序无关(按每个高度考虑)。

从高到低考虑杆,设此时的状态为\(S?\)\(S[i]?\)是高度\(i?\)的帆的数目,初始全为\(0?\),当前杆的高度为\(h?\),杆上需要放置的帆的数目为\(k?\),贪心地,假设两个高度的同等宜选,优先选择更高的;帆尽量放置在\(S[i]=0(i\le h)?\)的高度上,若还有剩余,设剩下\(t(t\le k)?\)个,则放置在除去以选择的高度以外,\(S[i](i\le h)?\)\(t?\)小的位置。

整理一下,每次选出\(S[1\cdots h]\)中前\(k\)小的(相同大小选下标较大的)高度放置帆。

{5,3} 0 0 1 1 1  +0
{4,3} 1 1 2 1 1  +1
{4,1} 1 2 2 1 1  +1
{3,2} 2 2 3 1 1  +3
{3,2} 3 3 3 1 1  +4
{2,1} 3 4 3 1 1  +3

但是此时\(S?\)似乎不好维护。。考虑将过程倒过来,从低到高考虑杆,(\(S?\)一开始为空集,其余定义相同),假设两个高度同等宜选,优先选择更低的,其余大致相同。即每次选出\(S[1\cdots h]?\)中前\(k?\)小的(相同大小选下标较小的)高度放置帆。

{2,1} 1 0        +0
{3,2} 1 1 1      +0
{3,2} 2 2 1      +2
{4,1} 2 2 1 1    +0
{4,3} 3 2 2 2    +4
{5,3} 3 3 3 2 1  +4

这样把\(B\)看成动态插入(长度变化时补0),每次查询全局前\(k\)小然后整体加一即可。(省去了下标范围的约束)。进一步可发现,连下标都不用维护了

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;


struct node {
    int siz,fa,ch[2];
    int sum,val,add;
} t[N];
int root,tot;
#define ls t[x].ch[0]
#define rs t[x].ch[1]
void upd(int x) {
    t[x].siz=t[ls].siz+t[rs].siz+1;
    t[x].sum=t[ls].sum+t[rs].sum+t[x].val;
}
void add(int x,int w) {if(x) t[x].add+=w,t[x].val+=w,t[x].sum+=t[x].siz*w;}
void psd(int x) {if(t[x].add) add(ls,t[x].add),add(rs,t[x].add),t[x].add=0;}
bool get(int x) {return t[t[x].fa].ch[1]==x;}
void rtt(int x) {
    int y=t[x].fa,k=get(x); if(t[y].fa) t[t[y].fa].ch[get(y)]=x;
    t[x].fa=t[y].fa;t[t[x].ch[k^1]=t[t[y].ch[k]=t[x].ch[k^1]].fa=y].fa=x;upd(y); 
}
void spl(int x,int d) {
    for(; t[x].fa!=d; rtt(x)) if(t[t[x].fa].fa!=d) 
        rtt(get(x)^get(t[x].fa)?x:t[x].fa);
    upd(x); if(d==0) root=x; 
}
void insert(int w) {
    int x=root,d=0;
    while(x) x=t[d=x].ch[t[x].val<w];
    x=++tot,t[x]=(node){1,d,{0,0},w,w,0};
    if(d) t[d].ch[t[d].val<w]=x; spl(x,0);
}
int kth(int k) {
    int x=root;
    while("orz") {
        psd(x);
        if(k>t[ls].siz+1) k-=t[ls].siz+1,x=rs;
        else if(k==t[ls].siz+1) return x;
        else x=ls;
    }
}

void show(int x) {
    if(!x) return;
    show(t[x].ch[0]),printf("%d ",t[x].val),show(t[x].ch[1]); 
}
void write(int x) {show(x); putchar('\n');}

int n;
long long ans;
pair<int,int> a[N];

int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; ++i) scanf("%d%d",&a[i].first,&a[i].second);
    a[0]=make_pair(0,0),sort(a+1,a+n+1);
    insert(-1e9),insert(1e9);
    for(int i=1; i<=n; ++i) {
        for(int t=a[i].first-a[i-1].first; t--;) insert(0);
        int x=kth(1),y=kth(a[i].second+2);
        spl(x,0),spl(y,x); 
        /*还有点东西没写完tat*/
    }
    printf("%lld\n",ans);
    return 0;
}
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++雾中风景13:volatile解惑 下一篇C++构造函数及成员变量

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目