bzoj1178/luogu3626 会议中心 (倍增+STL::set)

贪心地,可以建出一棵树,每个区间对应一个点,它的父亲是它右边的、与它不相交的、右端点最小的区间。

为了方便,再加入一个[0,0]区间

于是就可以倍增来做出从某个区间开始,一直到某个右界,这之中最多能选多少区间

这样的话,可以从[0,0]区间,倍增做出第一问的答案

考虑第二问,我们需要尽量选编号小的区间,于是只要判断我们如果选了这个区间 还能不能选够那么多就可以了

而且前面已经选过的就钦定住了

开一个set来放下已经选过的区间,按左端点从小到大排序

为了方便,一开始先把[0,0]区间和[inf,inf]区间加进去。设当前区间是x

这样的话,只要找到前驱pre、后继nxt,判断pre、nxt是否和x相交,相交就不做了

然后看从pre到nxt能选几个、(pre到x)+(x到nxt)+1能选几个,看看是否相等,来判断选不选x

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=2e5+10,inf=1e9+1;
 7 
 8 inline ll rd(){
 9     ll x=0;char c=getchar();int neg=1;
10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
12     return x*neg;
13 }
14 
15 struct Node{
16     int l,r,i;
17     Node (int a=0,int b=0,int c=0){l=a,r=b,i=c;}
18 }pos[maxn],pos2[maxn],pos3[maxn];
19 bool operator < (Node a,Node b){return a.l<b.l;}
20 int N,M;
21 int ma[maxn*2],fa[maxn][20],cnt[maxn][20];
22 set<Node> st;
23 bool flag[maxn];
24 
25 inline bool cmp(Node a,Node b){return a.l<b.l;}
26 inline bool cmp2(Node a,Node b){return a.r<b.r;}
27 
28 inline int getst(int x,int bnd){
29     int re=0;
30     for(int i=18;i>=0;i--){
31         if(fa[x][i]&&pos2[fa[x][i]].r<bnd)
32             re+=cnt[x][i],x=fa[x][i];
33     }
34     return re;
35 }
36 
37 int main(){
38     //freopen("","r",stdin);
39     int i,j,k;
40     N=rd();
41     for(i=1,j=0;i<=N;i++){
42         pos[i].l=rd(),pos[i].r=rd();pos[i].i=i;
43     }
44     memcpy(pos2,pos,sizeof(pos));
45     memcpy(pos3,pos,sizeof(pos));
46     sort(pos+1,pos+N+1,cmp);
47     sort(pos3+1,pos3+N+1,cmp2);
48     int mm=inf,mi=0;
49     for(i=N,j=N;i;i--){
50         for(;pos[j].l>pos3[i].r;j--){
51             if(pos[j].r<mm) mm=pos[j].r,mi=pos[j].i;
52         }
53         int x=pos3[i].i;
54         fa[x][0]=mi;cnt[x][0]=1;
55         // printf("%d %d\n",x,fa[x][0]);
56         for(k=0;fa[x][k]&&fa[fa[x][k]][k];k++){
57             fa[x][k+1]=fa[fa[x][k]][k];
58             cnt[x][k+1]=cnt[x][k]+cnt[fa[x][k]][k];
59         }
60     }
61     fa[N+1][0]=pos3[1].i;cnt[N+1][0]=1;
62     for(k=0;fa[N+1][k]&&fa[fa[N+1][k]][k];k++){
63         fa[N+1][k+1]=fa[fa[N+1][k]][k];
64         cnt[N+1][k+1]=cnt[N+1][k]+cnt[fa[N+1][k]][k];
65     }
66     printf("%d\n",getst(N+1,inf));
67     
68     st.insert(Node(0,0,N+1));st.insert(Node(inf,inf,N+2));
69     for(i=1;i<=N;i++){
70         set<Node>::iterator it=st.lower_bound(pos2[i]);
71         Node nxt=*it;
72         Node pre=*(--it);
73         if(nxt.l<=pos2[i].r||pre.r>=pos2[i].l) continue;
74         int n1=getst(pre.i,pos2[i].l)+getst(i,nxt.l)+1;
75         int nn=getst(pre.i,nxt.l);
76         // printf("%d %d %d %d %d\n",i,pre.i,nxt.i,nn,n1);
77         if(n1<nn) continue;
78         flag[i]=1;
79         st.insert(pos2[i]);
80     }
81     for(i=1;i<=N;i++) if(flag[i]) printf("%d ",i);
82     return 0;
83 }

 

转载于:https://www.cnblogs.com/Ressed/p/9759688.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值