蒟蒻求助一个关于权值线段树做法的特判问题

P3586 [POI2015] LOG

wind_whisper @ 2021-09-09 22:33:56

本题关键性质相信各位dl已经推出来了,就不啰嗦了
关于实现我想到的做法是权值线段树
离散化一下后把权值线段树按s的为界一分为二,左边求和,右边求数的个数
然而一交只有九十分....
经过一番无头苍蝇般的尝试之后我发现我如果特判一下如果当前有值的数的个数<c直接返回无解就过掉了

    if(tot>=1ll*x[i]*y[i]&&x[i]<=nnum)      printf("TAK\n");
    else printf("NIE\n");

(下面nnum就是有值的个数)
但我不太理解为什么需要这么做... 似乎如果有值的数少于c个,最后我计算tot的时候它一定会小于c*s吧...(显然每个数的贡献最多是s)
我不明白了 ...qwq
求大佬指点迷津

完整代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int N=1e6+100;
const int M=2e5+100;
const int mod=998244353;
int n,m;
inline ll read(){
    ll x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
ll tr[N<<2],siz[N<<2];
char s;
int op[N],x[N],y[N];
int q[N],num,cnt;
int a[N];
void pushup(int k){
    tr[k]=tr[ls]+tr[rs];siz[k]=siz[ls]+siz[rs];
}
void change(int k,int l,int r,int x,int v){
    //if(k==1) printf("x=%d v=%d\n",x,v);
    if(l==r){
        tr[k]+=v;siz[k]+=v>0?1:-1;
        //printf("  k=%d l=%d r=%d x=%d v=%d tr=%lld siz=%lld\n",k,l,r,x,v,tr[k],siz[k]);
        return;
    }
    if(x<=mid) change(ls,l,mid,x,v);
    else change(rs,mid+1,r,x,v);
    pushup(k);
    //printf("  k=%d l=%d r=%d x=%d v=%d tr=%lld siz=%lld\n",k,l,r,x,v,tr[k],siz[k]);
}
ll o;
ll find(int k,int l,int r,int p){
    //if(p==0) return 0;
    if(l==r) return tr[k];
    if(p>mid){
        ll res=tr[ls]+find(rs,mid+1,r,p);
        //printf("1:l=%d r=%d mid=%d res=%lld\n",l,r,mid,res);
        return res;
    }
    else{
        ll res=find(ls,l,mid,p)+siz[rs]*o;
        //printf("2:l=%d r=%d mid=%d res=%lld\n",l,r,mid,res);
        return res;
    }
}
int nnum;
signed main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        scanf(" %c",&s);x[i]=read();y[i]=read();
        op[i]=s=='U';
        if(op[i]){
            q[++num]=y[i];
            //printf("num=%d y=%d\n",num,y[i]);
        }
    }
    sort(q+1,q+1+num);
    cnt=unique(q+1,q+1+num)-q-1;
    //for(int i=1;i<=cnt;i++) printf("%d ",q[i]);
    //printf("cnt=%d\n",cnt);
    for(int i=1;i<=m;i++){
        if(op[i]){
            //printf("%d->%d\n",x[i],y[i]);
            int pl=lower_bound(q+1,q+1+cnt,y[i])-q;
            if(!y[i]) nnum-=a[x[i]]?1:0;
            else nnum+=a[x[i]]?0:1;
            if(a[x[i]]) change(1,1,cnt,a[x[i]],-q[a[x[i]]]);
            a[x[i]]=pl;
            change(1,1,cnt,pl,q[pl]);
        }
        else{
//          if(y[i]<q[1]){
//              printf("NIE\n");continue;
//          }
            int p=upper_bound(q+1,q+1+cnt,y[i])-q-1;
            o=y[i];
            //printf("---------find:\n");
            ll tot=find(1,1,cnt,p);
            //printf("num=%d tim=%d pl=%d tot=%lld\n",x[i],y[i],p,tot);
            if(tot>=1ll*x[i]*y[i]&&x[i]<=nnum) printf("TAK\n");
            else printf("NIE\n");
        }
    }
    return 0;
}
/*
3 10
U 1 5
U 2 7
U 3 0
U 2 0
U 2 7
U 3 1
Z 2 5
U 2 2
Z 2 6
Z 2 1
*/

(define int longlong 不可取) ~~(因为我实在是调磕了)


|