1. 程式人生 > >借教室_差分樹狀陣列

借教室_差分樹狀陣列

    這道題算是一道需要考慮優化演算法的題了。

讀題,不難發現需要求出的答案是第一個滿足不了的訂單,所以可以考慮二分快速查詢這時,不難想到一個普素演算法30分,直接暴力check不就好了。

#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],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; }
View Code

預期: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了這道題。。後悔