借教室_差分树状数组

    这道题算是一道需要考虑优化算法的题了。

读题,不难发现需要求出的答案是第一个满足不了的订单,所以可以考虑二分快速查找这时,不难想到一个普素算法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了这道题。。后悔

posted @ 2018-12-22 16:42  chdy  阅读(257)  评论(0编辑  收藏  举报