cogs1682. [HAOI2014]貼海報 x
阿新 • • 發佈:2017-07-13
math cst ima n) esp style 現在 amp cto
1682. [HAOI2014]貼海報
★★☆ 輸入文件:ha14d.in
輸出文件:ha14d.out
簡單對比
時間限制:1 s 內存限制:256 MB
【題目描述】
Bytetown城市要進行市長競選,所有的選民可以暢所欲言地對競選市長的候選人發表言論。為了統一管理,城市委員會為選民準備了一個張貼海報的electoral墻。
張貼規則如下:
1.electoral墻是一個長度為N個單位的長方形,每個單位記為一個格子;
2.所有張貼的海報的高度必須與electoral墻的高度一致的;
3.每張海報以“A B”表示,即從第A個格子到第B個格子張貼海報;
4.後貼的海報可以覆蓋前面已貼的海報或部分海報。
現在請你判斷,張貼完所有海報後,在electoral墻上還可以看見多少張海報。
【輸入格式】
第一行: N M 分別表示electoral墻的長度和海報個數
接下來M行: Ai Bi 表示每張海報張貼的位置
【輸出格式】
輸出貼完所有海報後,在electoral墻上還可以看見的海報數。
【樣例輸入】
100 5
1 4
2 6
8 10
3 4
7 10
【樣例輸出】
4
【提示】
【約束條件】
1 0<= N <= 10000000 1<=M<=1000 1<= Ai <= Bi <=10000000
所有的數據都是整數。數據之間有一個空格
思路:
1)首先這道題暴力可以拿80分!(在luogu上可以AC!!!!)
2)然後考場上作死寫了個並查集。。。61分
3)正解:
①線段樹(然而我沒寫~)
②浮水法
坑點:
因為給出的是所位於的塊,不是左右端點,所以在處理浮水法的時候記得要右端點+1,或者左端點-1
上代碼:
1)暴力
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> using namespace std; const int M = 1e7 + 1; int n,m,l,r,ans; int a[M],v[M]; inline int reads() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘ || ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘) {x=10*x+ch-‘0‘;ch=getchar();} return x*f; } int main() { freopen("ha14d.in","r",stdin); freopen("ha14d.out","w",stdout); n=reads(),m=reads(); for(int i=1;i<=m;i++) { l=reads(),r=reads(); if(r<l) swap(l,r); for(int j=l;j<=r;j++) a[j]=i; } for(int i=1;i<=n;i++) { if(!v[a[i]] && a[i]) { ans++; v[a[i]]=1; } } printf("%d",ans); return 0; }
2)作死並查集
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> using namespace std; inline int reads() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘ || ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘) {x=10*x+ch-‘0‘;ch=getchar();} return x*f; } const int M = 1e7 + 2333333; ///多開幾個 const int N = 1111; int n,m; int f[M]; int ans[M],anse; int Ls[N],Rs[N]; int getf(int x) {return f[x] == x ? x : f[x] = getf(f[x]);} int main() { freopen("ha14d.in","r",stdin); freopen("ha14d.out","w",stdout); n=reads();m=reads(); ///n是n塊,不是左右端點!!! for(int i=1;i<=n+2;i++) f[i]=i; for(int i=1;i<=m;i++) ///m組數據 { ///手動從1開始,從0不會... Ls[i]=reads(); Rs[i]=reads()+1; ///因為給出不是點的坐標,是塊的坐標 } int l,r; for(int i=m;i>=1;i--) ///逆序張貼,因為只需要的是最後的能看到的海報 { l=Ls[i],r=Rs[i]; ///左右端點 if(l>r) swap(l,r); ///maybe?會出現"left">"right"的情況(考慮最壞情況,以防萬一,以前做過一個題就是惡心的數據!) for(int j=getf(l);j<=r;j=getf(j+1)) { f[getf(j)]=getf(j+1); ///將當前被張貼報紙的父結點手動設置到最後一個的父結點 /// ans[j]=i; ans[i]++; if(getf(1)==n+2) break; ///表示已經貼完 } } for(int i=1;i<=n+1;i++) { /// printf("%d=%d\n",i,ans[i]); ///輸出調試??? if(ans[i]) anse++; } printf("%d\n",anse); return 0; }
3)正解(浮水法)
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; const int M = 1001; int n,m,ans=1; bool v[M]; struct U { int l,r,id; //id 為第幾張海報 }t[M]; inline int reads() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘ || ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘) {x=10*x+ch-‘0‘;ch=getchar();} return x*f; } void swim(int ql,int qr,int nowid,int preid) { if(v[preid]) return; while(nowid<=m && (qr<=t[nowid].l || ql>=t[nowid].r)) nowid++; if(nowid>m) { v[preid]=true; ans++; return; } if(ql<t[nowid].l && qr>t[nowid].l) swim(ql,t[nowid].l,nowid+1,preid); if(ql<t[nowid].r && qr>t[nowid].r) swim(t[nowid].r,qr,nowid+1,preid); } int main() { freopen("ha14d.in","r",stdin); freopen("ha14d.out","w",stdout); n=reads();m=reads(); for(int i=1;i<=m;i++) { t[i].l=reads(),t[i].r=reads()+1; t[i].id=i; } for(int i=m-1;i>=1;i--) swim(t[i].l,t[i].r,i+1,i); printf("%d",ans); return 0; }
cogs1682. [HAOI2014]貼海報 x