借教室_差分樹狀陣列
阿新 • • 發佈:2018-12-22
這道題算是一道需要考慮優化演算法的題了。
讀題,不難發現需要求出的答案是第一個滿足不了的訂單,所以可以考慮二分快速查詢這時,不難想到一個普素演算法30分,直接暴力check不就好了。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #includeView Code<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> #include<bitset> #include<bits/stdc++.h> using namespace std; inline int read() { 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=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int MAXN=1000002; int n,m; int a[MAXN],b[MAXN]; int d[MAXN],x[MAXN],y[MAXN]; int check(int p) { memset(b,0,sizeof(b)); for(int i=1;i<=p;i++) { for(int j=x[i];j<=y[i];j++) { b[j]+=d[i]; if(b[j]>a[j])return 0; } } return 1; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=m;i++) { d[i]=read(); x[i]=read(); y[i]=read(); } int l=1,r=m+1; while(l+1<r) { int mid=(l+r)>>1; if(check(mid)==0)r=mid; else l=mid; } if(check(r)==1&&r==m+1){put(0);return 0;} else put(-1); if(check(l)==0){put(l);} else {put(r);} return 0; }
預期:30分,實測40分。注意二分是r邊界是m+1,並非n+1,腦殘的我打程式碼時打成了n+1。
對於70分資料我不知道為什麼直接想這個是統計的可以字首和優化,但是這個貌似不行,那樹狀陣列可以差分一下區間修改單點查詢啊,最後1~n查一遍不就好了。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> #include<bitset> #include<bits/stdc++.h> using namespace std; inline int read() { 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=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int MAXN=1000002; int n,m; int a[MAXN]; int d[MAXN],x[MAXN],y[MAXN]; int c[MAXN]; void add(int x,int y){for(;x<=n;x+=x&(-x))c[x]+=y;} int ask(int x) { int ans=0; for(;x;x-=x&(-x))ans+=c[x]; return ans; } int check(int p) { memset(c,0,sizeof(c)); for(int i=1;i<=p;i++) { add(x[i],d[i]); add(y[i]+1,-d[i]); } for(int i=1;i<=n;i++)if(ask(i)>a[i])return 0; return 1; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=m;i++) { d[i]=read(); x[i]=read(); y[i]=read(); } int l=1,r=m+1; while(l+1<r) { int mid=(l+r)>>1; if(check(mid)==0)r=mid; else l=mid; } if(check(r)==1&&r==m+1){put(0);return 0;} else put(-1); if(check(l)==0){put(l);} else {put(r);} return 0; }View Code
預期70分,實測85。注意不能r寫成m+1時還不能check,要不樹狀陣列lowbit(0)瘋狂TLE,而腦殘的我就這樣瘋狂TLE了。
r寫成m+1時且不check(r)時可得95分。
最後一個點的優化。。當然還是本人自己想出來的,這個很容易想,二分出來的p值一直都是從1~n的而c陣列每次二分都要清0再重新賦值這不就慢很多了麼。
所以可以考慮不修改,直接進行賦值即可。就是加一個逆操作,c陣列不變。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> #include<bitset> #include<bits/stdc++.h> using namespace std; inline long long read() { long long x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(long long x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; long long num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const long long MAXN=1000002; long long n,m; long long a[MAXN]; long long d[MAXN],x[MAXN],y[MAXN]; long long c[MAXN]; long long prev=0; void add(long long x,long long y){for(;x<=n;x+=x&(-x))c[x]+=y;} long long ask(long long x) { long long ans=0; for(;x;x-=x&(-x))ans+=c[x]; return ans; } long long check(long long p) { if(p>prev) for(long long i=prev+1;i<=p;i++) { add(x[i],d[i]); add(y[i]+1,-d[i]); } else for(long long i=prev;i>p;i--) { add(x[i],-d[i]); add(y[i]+1,d[i]); } prev=p; for(long long i=1;i<=n;i++)if(ask(i)>a[i])return 0; return 1; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(long long i=1;i<=n;i++)a[i]=read(); for(long long i=1;i<=m;i++) { d[i]=read(); x[i]=read(); y[i]=read(); } long long l=1,r=m+1; while(l+1<r) { long long mid=(l+r)>>1; if(check(mid)==0)r=mid; else l=mid; } if(r==m+1){put(0);return 0;} else put(-1); if(check(l)==0)put(l); else put(r); return 0; }View Code
就這樣成功優化成功了,要不是m打成n了,而且還check(r)了,我不用點題解也能a了這道題。。後悔