码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 92 (Rated for Div. 2) 选讲

时间:2020-08-04 09:49:31      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:端点   hide   cli   onclick   nod   signed   code   线段树   alt   

https://codeforces.ml/contest/1389/problem/F

法一:dp,所有区间按右端点排序,依次考虑“如果最后一个区间为该区间”的最优情况,它(叫做A)可以从一个“右端点比A的左端点小”的异类区间B转移过来,但是同时可以顺便把“B的右端点以右”的同类区间算上。算上同类区间可以用线段树维护:每次计算完一个区间[L,R]后,把右端点小于L的所有异类区间的dp值+1。

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4  
 5 int n;
 6 const int maxn=400011;
 7  
 8 struct SEG
 9 {
10     int l,r,t;
11     bool operator < (const SEG &b) const
12     {
13         return r<b.r;
14     }
15 }seg[maxn];
16 int lisa[maxn<<1],li=0;
17  
18 int dp[maxn],contain[maxn];
19 struct SmtNode{int Max,add;};
20 struct SMT
21 {
22     SmtNode a[maxn<<2];
23     int n;
24     SMT() {n=0;}
25     void clear(int N) {n=N;}
26 //    int ls(int x) {return x<<1;}
27 //    int rs(int x) {return (x<<1)|1;}
28     #define ls(x) (x<<1)
29     #define rs(x) ((x<<1)|1)
30     void up(int x) {a[x].Max=max(a[ls(x)].Max,a[rs(x)].Max);}
31     void addsingle(int x,int v) {a[x].Max+=v; a[x].add+=v;}
32     void down(int x) {if (a[x].add>0) {addsingle(ls(x),a[x].add); addsingle(rs(x),a[x].add); a[x].add=0;} }
33     void Insert(int x,int L,int R,int p,int v)
34     {
35         if (L==R) {a[x].Max=max(a[x].Max,v); return;}
36         down(x);
37         int mid=(L+R)>>1;
38         if (p<=mid) Insert(ls(x),L,mid,p,v);
39         else Insert(rs(x),mid+1,R,p,v);
40         up(x);
41     }
42     void insert(int p,int v) {Insert(1,0,n,p,v);}
43     int QPreMax(int x,int L,int R,int p)
44     {
45         if (R<=p) return a[x].Max;
46         down(x);
47         int mid=(L+R)>>1;
48         if (p<=mid) return QPreMax(ls(x),L,mid,p);
49         return max(QPreMax(ls(x),L,mid,p),QPreMax(rs(x),mid+1,R,p));
50     }
51     int qPreMax(int p) {return QPreMax(1,0,n,p);}
52     void Add(int x,int L,int R,int ql,int qr,int v)
53     {
54         if (ql<=L && R<=qr) {addsingle(x,v); return;}
55         down(x);
56         int mid=(L+R)>>1;
57         if (ql<=mid) Add(ls(x),L,mid,ql,qr,v);
58         if (qr>mid) Add(rs(x),mid+1,R,ql,qr,v);
59         up(x);
60     }
61     void add(int L,int R,int v) {if (L<=R) Add(1,0,n,L,R,v);}
62 }s[2];
63  
64 int main()
65 {
66     scanf("%d",&n);
67     for (int i=1;i<=n;i++)
68     {
69         scanf("%d%d%d",&seg[i].l,&seg[i].r,&seg[i].t);
70         seg[i].t--;
71         lisa[++li]=seg[i].l;
72         lisa[++li]=seg[i].r;
73     }
74     sort(lisa+1,lisa+1+li); li=unique(lisa+1,lisa+1+li)-lisa-1;
75     for (int i=1;i<=n;i++)
76     {
77         seg[i].l=lower_bound(lisa+1,lisa+1+li,seg[i].l)-lisa;
78         seg[i].r=lower_bound(lisa+1,lisa+1+li,seg[i].r)-lisa;
79     }
80     sort(seg+1,seg+1+n);
81 //    for (int i=1;i<=n;i++) cout<<"NO"<<i<<‘ ‘<<seg[i].l<<‘ ‘<<seg[i].r<<‘ ‘<<seg[i].t<<endl;
82     
83     s[0].clear(li); s[1].clear(li);
84     dp[0]=0;
85     for (int i=1;i<=n;i++)
86     {
87         bool ty=seg[i].t;
88         dp[i]=s[ty^1].qPreMax(seg[i].l-1)+1;
89         s[ty].insert(seg[i].r,dp[i]);
90         s[ty^1].add(0,seg[i].l-1,1);
91 //        cout<<i<<‘ ‘<<dp[i]<<endl;
92     }
93     
94     int ans=0;
95     for (int i=1;i<=n;i++) ans=max(ans,dp[i]);
96     printf("%d\n",ans);
97     return 0;
98 }
View Code

法二:每个区间看作一个结点,会冲突的区间都连一条边,会形成一个二分图,目标是找最大独立集,转换为找最大匹配。复杂度不允许用二分图的算法。可将1类的区间按右端点升序,依次考虑能否匹配,对每个1类区间A,在所有能与之匹配的2类区间中贪心找右端点最小的即可。(枚举1类区间A的过程中会将“左端点小于A的右端点”的2类区间的右端点不停地丢入数据结构中,我们希望数据结构中存留下来的这些“右端点”们尽可能大,才能满足后面更大的“1类区间的左端点”)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 
 5 int n;
 6 struct SEG{int l,r;};
 7 vector<SEG> seg[2];
 8 multiset<int> s;
 9 
10 int main()
11 {
12     scanf("%d",&n);
13     for (int i=1,l,r,t;i<=n;i++)
14     {
15         scanf("%d%d%d",&l,&r,&t);
16         seg[t-1].push_back((SEG){l,r});
17     }
18     sort(seg[0].begin(),seg[0].end(),[](SEG a,SEG b) {return a.r<b.r;});
19     sort(seg[1].begin(),seg[1].end(),[](SEG a,SEG b) {return a.l<b.l;});
20     
21 //    cout<<endl;
22     unsigned int j=0,ans=n;
23     for (SEG x:seg[0])
24     {
25         while (j<seg[1].size() && seg[1][j].l<=x.r) s.insert(seg[1][j].r),j++;
26         auto it=s.lower_bound(x.l);
27         if (it==s.end()) continue;
28 //        cout<<x.l<<‘ ‘<<x.r<<‘ ‘<<*it<<endl;
29         s.erase(it);
30         ans--;
31     }
32     printf("%d\n",ans);
33     return 0;
34 }
View Code

 

Educational Codeforces Round 92 (Rated for Div. 2) 选讲

标签:端点   hide   cli   onclick   nod   signed   code   线段树   alt   

原文地址:https://www.cnblogs.com/Blue233333/p/13430868.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!