【思维+树状数组

mac2024-06-04  35

题意:

给n个线段,我们需要保证每个点(只考虑整数点)的重复不超过k次,让我们找出要剔除的线段,并输出这些线段的位置。

D1. Too Many Segments (easy version)

思路:

没有思路,要说思路就是暴力!(哈哈)真的是纯暴力

就是将一个线段分别以每个整数点为起点,右端点为终点,分为len个线段,都存起来。并且按照新的左端点升序,左端点相同线段长度降序排序。然后遍历一遍所有的线段,如果有不符合条件的就把这个子线段所在的原线段删掉【因为是按照长度降序排序的,所以贪心删掉最长的】。然后再存一下删掉线段的序号即可。 #include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <string> #include <vector> #include <set> #include <stack> #include <list> #include <map> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxN = 2e5 + 5; struct node{ int l, r, len, id; friend bool operator < (node n1, node n2) { if(n1.l == n2.l) return n1.len > n2.len; return n1.l < n2.l; } }info[maxN]; int num[maxN] ,vis[maxN], ans[maxN]; void init() { memset(num, 0, sizeof(num)); memset(vis, 0, sizeof(vis)); memset(ans, 0, sizeof(ans)); } int main() { int n, k; while(~scanf("%d%d", &n, &k)) { int cnt = 0; init(); for(int i = 1; i <= n; i ++ ) { int a, b; scanf("%d%d", &a, &b); for(int j = a; j <= b; j ++ ) { info[cnt ++ ] = node{j, b, b - j + 1, i}; num[j] ++; } } sort(info, info + cnt); int pos = 0; for(int i = 0; i < cnt; i ++ ) { if(vis[info[i].id]) continue; if(num[info[i].l] > k) { for(int j = info[i].l; j <= info[i].r; j ++ ) num[j] -- ; vis[info[i].id] = 1; ans[pos ++ ] = info[i].id; } } sort(ans, ans + pos); printf("%d\n", pos); for(int i = 0; i < pos; i ++ ) printf("%d%c", ans[i], " \n"[i == pos - 1]); } return 0; }

D2. Too Many Segments (hard version)

思路

记录下输入的最左和最右的端点,跑for( i = L, i <= R )循环,以 i 为右端点,将左端点在 i 之前的线段都 insert,然后我们从这些线段里剔除右端点最靠右的几个,使得该点的出现频率 == k.【这里用到了贪心的思想,越往右,覆盖的点越多】在剔除线段之前,我们需要将右端点小于 i 的线段踢出去,因为前边的已经满足出现频率在 k 之内了【维护整数点的频率】用到了树状数组的区间更新,单点查询。【差分思想】

差分_树状数组

D[maxN]: D[ i ]表示 A[ i ] - A[ i - 1 ]求A[ i ] = D[ i ] + D[ i - 1 ] + D[ i - 2 ] + … + D[ 1 ] #include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <string> #include <vector> #include <set> #include <stack> #include <list> #include <map> #define INF 0x3f3f3f3f #define lowbit(x) x & (- x) using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxN = 2e5 + 5; int n, k; struct node{ int l, r, id; node(int a = 0, int b = 0, int c = 0) : l(a), r(b), id(c) {} friend bool operator < (node n1, node n2) { return n1.r > n2.r ; } }info[maxN]; bool cmp(node n1, node n2) { return n1.l < n2.l; } int L, R; int D[maxN]; void add(int x, int val) { while(x <= R) { D[x] += val; x += lowbit(x); } } int getsum(int x) { int ans = 0; while(x > 0) { ans += D[x]; x -= lowbit(x); } return ans; } int main() { scanf("%d%d", &n, &k); L = INF, R = 0; for(int i = 1; i <= n; i ++ ) { scanf("%d%d", &info[i].l, &info[i].r); info[i].id = i; L = min(L, info[i].l); R = max(R, info[i].r); } for(int i = 1; i <= n; i ++ ) { add(info[i].l, 1); add(info[i].r + 1, -1); } sort(info + 1, info + n + 1, cmp); multiset<node>st; set<int>ans; int pos = 1; for(int i = L; i <= R; i ++ ) { if(getsum(i) <= k) continue; while(info[pos].l <= i && pos <= n) { st.insert(info[pos]); pos ++; } while(!st.empty() && (*st.rbegin()).r < i) st.erase(*st.rbegin()); while(st.size() > k) { node tmp = *st.begin(); ans.insert(tmp.id); st.erase(st.begin()); add(tmp.l, -1); add(tmp.r + 1, 1); } } int cnt = ans.size(); printf("%d\n", cnt); while(!ans.empty()) { int tmp = *ans.begin(); printf("%d ", tmp); ans.erase(tmp); } printf("\n"); return 0; }
最新回复(0)