P3626 [APIO2009]会议中心

传送门

好迷的思路……

首先,如果只有第一问就是个贪心,排个序就行了

对于第二问,我们考虑这样的一种构造方式,每一次都判断加入一个区间是否会使答案变差,如果不会的话就将他加入别问我正确性我不会证

我们先把所有的区间按左端点排个序顺便把互相包含的区间去掉(毕竟互相包含的时候短的肯定比长的优),然后把所有已经被选的区间加入一棵set,然后在里面查找它左右两边的区间\([l1,r1]\)\([l2,r2]\),那么如果选了这个区间就会影响\([l1+1,r2-1]\),设\(s[i][j]\)表示从\(i\)\(j\)能选多少个区间,那么加入之后不会使答案变差当且仅当
\[s[l1+1][r2-1]==s[l1+1][l-1]+s[r+1][r2-1]+1\]
然后\(s\)数组可以用倍增求出来,总的复杂度为\(O(nlogn)\)

然而还有个问题有点懵……原题解的代码里去掉互相包含的区间的时候是保留长的区间……然而也能A……不知道是我理解错了还是什么缘故……

//minamoto
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IT set<node>::iterator
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=2e5+5;
struct node{
    int l,r;
    inline bool operator <(const node &b)const
    {return l==b.l?r>b.r:l<b.l;}
    /*
        原题解里这里写的是{return r==b.r?l>b.l:r<b.r;}
        下面去重的写的是fp(i,1,n)if(t[i].l>t[m].l)t[++m]=t[i]; 
    */
}a[N],t[N];set<node>s;
int X[N],Y[N],nx[N][30],L[N],R[N],n,m,ans;
int calc(int l,int r){
    int x=lower_bound(X+1,X+1+m,l)-X;if(x>m||Y[x]>r)return 0;
    int res=1;
    fd(i,20,0)if(nx[x][i]&&Y[nx[x][i]]<=r)res+=1<<i,x=nx[x][i];
    return res;
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read();fp(i,1,n)t[i].l=read(),t[i].r=read(),a[i]=t[i];
    sort(t+1,t+1+n),m=0;
    fp(i,1,n){
        while(m&&t[i].r<=t[m].r)--m;
        t[++m]=t[i];
    }
    fp(i,1,m)X[i]=t[i].l,Y[i]=t[i].r;
    for(register int i=1,j=1;i<=m;++i){
        while(j<=m&&t[j].l<=t[i].r)++j;
        if(j<=m)nx[i][0]=j;
    }
    fp(j,1,20)fp(i,1,m)nx[i][j]=nx[nx[i][j-1]][j-1];
    printf("%d\n",ans=calc(-inf,inf));
    s.insert((node){inf,inf}),s.insert((node){-inf,-inf});
    fp(i,1,n){
        IT x=s.lower_bound(a[i]),y=x;--y;
        int l1=y->r,r1=a[i].l,l2=a[i].r,r2=x->l;
        if(l1>=r1||l2>=r2)continue;
        if(calc(l1+1,r2-1)==calc(l1+1,r1-1)+calc(l2+1,r2-1)+1)
        printf("%d ",i),s.insert(a[i]);
    }return 0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10031482.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值