省选专练之数据结构 [POI2011]MET-Meteors

10 篇文章 0 订阅
1 篇文章 0 订阅

第一次学习整体二分,我感觉这个复杂度玄学啊

莫队算法在变权的时候是不是和这个的Tim异曲同工?

明显答案相对独立

明显时间可以二分

经典整体二分

但是小心哲学数据点8metb

炸Long Long

#include<bits/stdc++.h>
using namespace std;
typedef int INT;
#define int long long 
const int INF=1e17+7;
const int N=3e5+500;
inline void read(int &x){
    x=0;
    char ch=getchar();
    int f=1;
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
int n,m;
vector<int>T[N];// 以国家的视角看下标 
int Loc[N]={};// 当前下标对应国家 
int Goal[N]={};//当前国家目标 陨石量 
int Belong[N]={};//该空间站属于什么国家 
int St[N]={};
int Ed[N]={};
int Val[N]={};
int ans[N]={};
int Get[N]={};//在二分时间点的陨石数 
int k; 
int tim=0;
int Lc[N]={};
int Rc[N]={};
//----------
int Tree[N]={};
const int maxn=300010;
inline int Lowbit(int x){
    return x&(-x);
}
inline void update(int x,int val){
    while(x<=m){
        Tree[x]+=val;
        x+=Lowbit(x);
    }
}
inline int Query(int x){
    int ret=0;
    while(x){
        ret+=Tree[x];
        x-=Lowbit(x);
    }
    return ret;
}
inline void Change(int St,int Ed,int Val){
//	cout<<St<<" "<<Ed<<" "<<Val<<'\n';
    if(St<=Ed){
        update(St,Val);
        update(Ed+1,-Val);
    }
    else{
        update(St,Val);
        update(m+1,-Val);
        update(1,Val);
        update(Ed+1,-Val);
//		Change(1,Ed,Val);
//		Change(St,m,Val);
    }
}
void Solve(int l,int r,int L,int R){
//	cout<<l<<" "<<r<<" "<<L<<" "<<R<<'\n';
    if(l>r)return;
    if(L>R)return;
    if(l==r){
        for(int i=L;i<=R;i++)
            ans[Loc[i]]=l;
        return;
    }
    int mid=(l+r)/2;
    while(tim<mid)tim++,Change(St[tim],Ed[tim],Val[tim]);
    while(tim>mid)Change(St[tim],Ed[tim],-Val[tim]),tim--;
//	cout<<"here"<<'\n';
    for(int i=L;i<=R;i++){
        Get[Loc[i]]=0;
        for(int j=0;j<T[Loc[i]].size();j++){
            Get[Loc[i]]+=Query(T[Loc[i]][j]);
            if(Get[Loc[i]]>Goal[Loc[i]])break;
        }
    }
// 	cout<<mid<<" "<<Get[1]<<'\n';
//	cout<<"here"<<'\n';
    int left_cnt=0;
    int right_cnt=0;
    for(int i=L;i<=R;i++){
        if(Get[Loc[i]]>=Goal[Loc[i]])Lc[++left_cnt]=Loc[i];
        else Rc[++right_cnt]=Loc[i];
    } 
    for(int i=1;i<=left_cnt;i++)Loc[i+L-1]=Lc[i];
    for(int i=1;i<=right_cnt;i++)Loc[i+left_cnt+L-1]=Rc[i];
    int Half=left_cnt;
    Solve(l,mid,L,L+Half-1);
    Solve(mid+1,r,L+Half,R);
}
INT main(){
//	freopen("met8b.in","r",stdin);
//	freopen("P3527.out","w",stdout);
    read(n);
    read(m);
    for(int i=1;i<=m;i++){
        read(Belong[i]);
        T[Belong[i]].push_back(i);
    }
    for(int i=1;i<=n;i++)read(Goal[i]),Loc[i]=i;
    read(k);
    for(int i=1;i<=k;i++){
        read(St[i]);
        read(Ed[i]);
        read(Val[i]);
    }
    k++;
    St[k]=1;
    Ed[k]=m;
    Val[k]=INF;
    Solve(1,k,1,n);
    for(int i=1;i<=n;i++){
        if(ans[i]==k)puts("NIE");
        else cout<<ans[i]<<'\n';
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值