zoukankan      html  css  js  c++  java
  • P3527 [POI2011]MET-Meteors 整体二分

      给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值

    非常好的整体二分模板题

    之前的修改和询问都是全部扔到结构体里面一起分治的 这题不用这样(因为是先修改后询问的) 所以只对询问进行分治即可 可以减少很多码量 (但之前的模板题不适合这样   之前二分的为值域 如果遍历值域的话复杂度太高了   这题二分的不是自然数值域 而是操作次数!)

    注意给定的是一个环  所以当处理左端点大于右端点的区间时  将右端点加上区间长度(也就是展开成一条链 ) 同时在树状数组询问的时候要加上两个值(一个值比另一个大m)

    二分的右界+1 当均不满足的时候 跳到右界+1

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=2e6+10;
    int n,m,ans[N],zuo[N],you[N],pos,head[N],k,x;
    ll v[N],t[N];
    struct Edge{int to,nex;}edge[N<<1];
    void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
    void upnode(int x,int v){for(;x<=N;x+=x&-x)t[x]+=v;}
    ll qsum(int x){ll ans=0;for(;x;x-=x&-x)ans+=t[x];return ans;}
    struct node{ll id,need;}s[N],temp1[N],temp2[N];
    
    void solve(int L,int R,int l,int r)
    {
        if(l>r)return ;
        if(L==R){rep(i,l,r)ans[s[i].id]=L;return ;}
        int mid=(L+R)>>1;
        rep(i,L,mid)upnode(zuo[i],v[i]),upnode(you[i]+1,-v[i]);
        int cnt1=0,cnt2=0;
        rep(i,l,r)
        {    
            ll sum=0;
            for(int j=head[s[i].id];j&&sum<=s[i].need;j=edge[j].nex)
            sum+=qsum(edge[j].to)+qsum(edge[j].to+m);
            if(sum>=s[i].need)temp1[++cnt1]=s[i];
            else temp2[++cnt2]=s[i],temp2[cnt2].need-=sum;
        }
        rep(i,L,mid)upnode(zuo[i],-v[i]),upnode(you[i]+1,v[i]);//谁污染谁治理
        
        rep(i,1,cnt1)s[l-1+i]=temp1[i];
        rep(i,1,cnt2)s[l+cnt1-1+i]=temp2[i];
        solve(L,mid,  l,l+cnt1-1);solve(mid+1,R,l+cnt1,r);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        rep(i,1,m)scanf("%d",&x),add(x,i);
        rep(i,1,n)scanf("%lld",&s[i].need),s[i].id=i;
        scanf("%d",&k);
        rep(i,1,k){scanf("%d%d%lld",&zuo[i],&you[i],&v[i]);if(you[i]<zuo[i])you[i]+=m;}
        solve(1,k+1,1,n);
        rep(i,1,n)
        if(ans[i]==k+1)printf("NIE
    ");
        else printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    restapi(6)- do it the functional way, 重温函数式编程
    JS模块化
    socket.io websocket
    CSS 文字换行
    webpack初识
    升级nodejs至最新
    JavaScript Promise迷你书(中文版)
    时间格式化
    npm yarn
    深入浅出MongoDB应用实战开发
  • 原文地址:https://www.cnblogs.com/bxd123/p/11547889.html
Copyright © 2011-2022 走看看