【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并)
生活随笔
收集整理的這篇文章主要介紹了
【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題干:
鏈接:https://ac.nowcoder.com/acm/contest/370/A
來源:牛客網
?
恭喜你找到了本場比賽的簽到題!
為了讓大家都有抽獎的機會,只需要復制粘貼以下代碼(并且稍微填下空)即可 AC:
(我超良心的)
輸入描述:
第一行兩個整數 N,L,意義如代碼所述。接下來 N 行,每行三個整數 opt,l,r,意義如代碼所述。輸出描述:
對于每一組 opt=3 的詢問輸出一個答案。示例1
輸入
復制
6 13 1 1 2 1 4 5 1 4 7 1 6 9 1 12 13 3 3 3輸出
復制
10說明
我們依次加入線段[1,2],[4,5],[4,7],[6,9],[12,13], 它們的并集長度為 10.備注:
N≤105,L≤105,0≤l≤r≤LN≤105,L≤105,0≤l≤r≤L,保證數據隨機生成。解題報告:
題目需要你維護一個線段集合,支持插入線段,刪除線段和求線段并長度。
我們可以用簡化版的掃描線來實現,當然因為數據隨機,暴力也可以過。。。。
AC代碼1:(直接暴力)(400ms-800ms)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 1e5 + 5; set<int> ss[MAX]; int vis[MAX]; int main() {int n,maxl,ans=0;scanf("%d%d", &n, &maxl);for(int i = 1; i<=n; i++) {int op,l,r;scanf("%d%d%d",&op,&l,&r);if(l > r) swap(l,r);if(op == 1) {if(ss[l].find(r)!=ss[l].end()) continue;ss[l].insert(r);for(int j = l; j<=r; j++) {if(vis[j] == 0) ans++;vis[j]++;}}if(op == 2) {if (ss[l].find(r)==ss[l].end()) continue;ss[l].erase(r);for(int j = l; j<=r; j++) {if(vis[j] == 1) ans--;vis[j]--;}}if(op == 3) printf("%d\n",ans);}return 0 ;}AC代碼2:(掃描線)(100ms)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; set<int> s[100005]; struct Tree {int l,r;int val;int laz; } tree[100005 * 4]; inline int len(int cur) {return tree[cur].r - tree[cur].l + 1; } void pushup(int cur) {if(tree[cur].laz > 0) tree[cur].val = len(cur);else if (tree[cur].l == tree[cur].r) tree[cur].val = 0;else tree[cur].val = tree[cur*2].val + tree[cur*2+1].val; } void pushdown(int cur) {if(tree[cur].laz == 0) return ;tree[cur*2].laz += tree[cur].laz;tree[cur*2+1].laz += tree[cur].laz;tree[cur*2].val += tree[cur].laz;tree[cur*2+1].val += tree[cur].laz;tree[cur].laz = 0; } void build(int l,int r,int cur) {tree[cur].val=0;tree[cur].l = l;tree[cur].r = r;if(l == r) return ;int m = (l+r)>>1;build(l,m,cur*2);build(m+1,r,cur*2+1); } void update(int pl,int pr,int val,int cur) {if(pl <= tree[cur].l && pr >= tree[cur].r) {tree[cur].laz += val;pushup(cur);return ;}//pushdown(cur);if(tree[cur*2].r >= pl) update(pl,pr,val,cur*2);if(tree[cur*2+1].l <= pr) update(pl,pr,val,cur*2+1);pushup(cur); } int main() {int ans=0,N,maxL;scanf("%d%d", &N, &maxL);build(1,maxL,1);while (N--) {int opt, x, y;scanf("%d%d%d", &opt, &x, &y);if (x>y) swap(x,y);if (opt == 1) {if (s[x].find(y)!=s[x].end()) continue;s[x].insert(y);update(x,y,1,1);}if (opt == 2) {if (s[x].find(y)==s[x].end()) continue;s[x].erase(y); update(x,y,-1,1);}if (opt == 3) {printf("%d\n", tree[1].val);}}return 0; }AC代碼3:(掃描線+pushdown版本)(應該是可以支持區間覆蓋情況查詢的)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; set<int> s[100005]; struct Tree {int l,r;int val;int laz; } tree[100005 * 4]; inline int len(int cur) {return tree[cur].r - tree[cur].l + 1; } void pushup(int cur) {if(tree[cur].laz > 0) tree[cur].val = len(cur);else if (tree[cur].l == tree[cur].r) tree[cur].val = 0;else tree[cur].val = tree[cur*2].val + tree[cur*2+1].val; } void pushdown(int cur) {if(tree[cur].laz == 0) return ;tree[cur*2].laz += tree[cur].laz;tree[cur*2+1].laz += tree[cur].laz; // tree[cur*2].val += tree[cur].laz; // tree[cur*2+1].val += tree[cur].laz; // tree[cur].laz = 0; } void build(int l,int r,int cur) {tree[cur].val=0;tree[cur].l = l;tree[cur].r = r;if(l == r) return ;int m = (l+r)>>1;build(l,m,cur*2);build(m+1,r,cur*2+1); } void update(int pl,int pr,int val,int cur) {if(pl <= tree[cur].l && pr >= tree[cur].r) {tree[cur].laz += val;pushup(cur);return ;}pushdown(cur);if(tree[cur*2].r >= pl) update(pl,pr,val,cur*2);if(tree[cur*2+1].l <= pr) update(pl,pr,val,cur*2+1);pushup(cur); } int main() {int ans=0,N,maxL;scanf("%d%d", &N, &maxL);build(1,maxL,1);while (N--) {int opt, x, y;scanf("%d%d%d", &opt, &x, &y);if (x>y) swap(x,y);if (opt == 1) {if (s[x].find(y)!=s[x].end()) continue;s[x].insert(y);update(x,y,1,1);}if (opt == 2) {if (s[x].find(y)==s[x].end()) continue;s[x].erase(y); update(x,y,-1,1);}if (opt == 3) {printf("%d\n", tree[1].val);}}return 0; }標程:
我們考慮一種非常暴力的做法:對于這個數軸建出線段樹,然后插入刪除對應了區間加值操作。
我們來考慮一下詢問操作:最樸素的方法是查詢每個點是否有值然后統計答案。我們可以考慮對每一個線段樹上的節點維護一個 min 值,這樣遍歷到一個節點的時候如果當前節點的 min > 0 那么說明這個線段樹節點對應的區間是所有線段并的一部分。
當然這樣的話還是不一定能過的,但是注意到數據隨機生成,所以查詢操作僅為總操作的1313 ,且刪除操作大概率不會觸發。
?
總結
以上是生活随笔為你收集整理的【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 靠档计息的为什么要取消?靠档计息叫停该怎
- 下一篇: 【EOlymp - 2908】SumTh