标签:端点 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 }
法二:每个区间看作一个结点,会冲突的区间都连一条边,会形成一个二分图,目标是找最大独立集,转换为找最大匹配。复杂度不允许用二分图的算法。可将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 }
Educational Codeforces Round 92 (Rated for Div. 2) 选讲
标签:端点 hide cli onclick nod signed code 线段树 alt
原文地址:https://www.cnblogs.com/Blue233333/p/13430868.html