日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并)

發(fā)布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題干:

鏈接:https://ac.nowcoder.com/acm/contest/370/A
來源:牛客網(wǎng)
?

恭喜你找到了本場比賽的簽到題!
為了讓大家都有抽獎的機會,只需要復制粘貼以下代碼(并且稍微填下空)即可 AC:
(我超良心的)

#include <algorithm>#include <iostream>#include <cstring>#include <climits>#include <cstdio>#include <vector>#include <cstdlib>#include <ctime>#include <cmath>#include <queue>#include <stack>#include <map>#include <set>#define fi first#define lc (x<<1)#define se second#define U unsigned#define rc (x<<1|1)#define Re register#define LL long long#define MP std::make_pair#define CLR(i,a) memset(i,a,sizeof(i))#define FOR(i,a,b) for(Re int i = a;i <= b;++i)#define ROF(i,a,b) for(Re int i = a;i >= b;--i)#define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c)#define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c)#define DEBUG(x) std::cerr << #x << '=' << x << std::endlconst int MAXN = 1000000+5;int N,maxL;std::set<std::pair<int,int> > L;inline int calc(){// 返回 set 中所有線段的并長度。(每個 pair 表示一個線段[first,second]}int main(){scanf("%d%d",&N,&maxL);while(N--){int opt,x,y;scanf("%d%d%d",&opt,&x,&y);if(opt == 1){if(L.find(MP(x,y)) != L.end()) continue;L.insert(MP(x,y));}if(opt == 2){if(L.find(MP(x,y)) == L.end()) continue;L.erase(MP(x,y));}if(opt == 3){printf("%d\n",calc());}}return 0;}

輸入描述:

第一行兩個整數(shù) N,L,意義如代碼所述。接下來 N 行,每行三個整數(shù) 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,保證數(shù)據(jù)隨機生成。

解題報告:

題目需要你維護一個線段集合,支持插入線段,刪除線段和求線段并長度。

我們可以用簡化版的掃描線來實現(xiàn),當然因為數(shù)據(jù)隨機,暴力也可以過。。。。

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版本)(應該是可以支持區(qū)間覆蓋情況查詢的)

#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; }

標程:

我們考慮一種非常暴力的做法:對于這個數(shù)軸建出線段樹,然后插入刪除對應了區(qū)間加值操作。
我們來考慮一下詢問操作:最樸素的方法是查詢每個點是否有值然后統(tǒng)計答案。我們可以考慮對每一個線段樹上的節(jié)點維護一個 min 值,這樣遍歷到一個節(jié)點的時候如果當前節(jié)點的 min > 0 那么說明這個線段樹節(jié)點對應的區(qū)間是所有線段并的一部分。
當然這樣的話還是不一定能過的,但是注意到數(shù)據(jù)隨機生成,所以查詢操作僅為總操作的1313 ,且刪除操作大概率不會觸發(fā)。

const int MAXN = 100000+5; #define lc (x<<1) #define rc (x<<1|1) int min[MAXN<<2],tag[MAXN<<2];inline void pushup(int x){min[x] = std::min(min[lc],min[rc]); }inline void cover(int x,int l,int r,int delta){min[x] += delta;tag[x] += delta; }inline void pushdown(int x,int l,int r){if(tag[x]){int mid = (l + r) >> 1;cover(lc,l,mid,tag[x]);cover(rc,mid+1,r,tag[x]);tag[x] = 0;} }inline void modify(int x,int l,int r,int L,int R,int delta){if(l == L && R == r){cover(x,l,r,delta);return;}pushdown(x,l,r);int mid = (l + r) >> 1;if(R <= mid) modify(lc,l,mid,L,R,delta);else if(L > mid) modify(rc,mid+1,r,L,R,delta);else modify(lc,l,mid,L,mid,delta),modify(rc,mid+1,r,mid+1,R,delta);pushup(x); }inline int query(int x,int l,int r){if(min[x] != 0) return r-l+1;if(l == r) return min[x] != 0;int mid = (l + r) >> 1;pushdown(x,l,r);return query(lc,l,mid)+query(rc,mid+1,r); }std::map<P,bool> S; int L = 0; int main(){int N;scanf("%d%d",&N,&L);while(N--){int opt,x,y;scanf("%d%d%d",&opt,&x,&y);if(opt == 1){if(S[MP(x,y)]) continue;S[MP(x,y)] = true;// L = std::max(L,y);modify(1,1,L,x,y,1);}if(opt == 2){if(!S[MP(x,y)]) continue;S[MP(x,y)] = false;modify(1,1,L,x,y,-1);}if(opt == 3){printf("%d\n",query(1,1,L));}}return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的【牛客 - 370A】签到题(线段树扫描线 或 STLset)(求线段并)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。